mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-16 21:20:00 +00:00
Merge pull request #405 from logos-blockchain/Pravdyvy/db-structural-updates
DB structural updates
This commit is contained in:
commit
951b06c0fd
96
storage/src/cells/mod.rs
Normal file
96
storage/src/cells/mod.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use borsh::{BorshDeserialize, BorshSerialize};
|
||||||
|
use rocksdb::{BoundColumnFamily, DBWithThreadMode, MultiThreaded, WriteBatch};
|
||||||
|
|
||||||
|
use crate::{DbResult, error::DbError};
|
||||||
|
|
||||||
|
pub mod shared_cells;
|
||||||
|
|
||||||
|
pub trait SimpleStorableCell {
|
||||||
|
const CF_NAME: &'static str;
|
||||||
|
const CELL_NAME: &'static str;
|
||||||
|
type KeyParams;
|
||||||
|
|
||||||
|
fn key_constructor(_params: Self::KeyParams) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&Self::CELL_NAME).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some(format!("Failed to serialize {:?}", Self::CELL_NAME)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn column_ref(db: &DBWithThreadMode<MultiThreaded>) -> Arc<BoundColumnFamily<'_>> {
|
||||||
|
db.cf_handle(Self::CF_NAME)
|
||||||
|
.unwrap_or_else(|| panic!("Column family {:?} must be present", Self::CF_NAME))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SimpleReadableCell: SimpleStorableCell + BorshDeserialize {
|
||||||
|
fn get(db: &DBWithThreadMode<MultiThreaded>, params: Self::KeyParams) -> DbResult<Self> {
|
||||||
|
let res = Self::get_opt(db, params)?;
|
||||||
|
|
||||||
|
res.ok_or_else(|| DbError::db_interaction_error(format!("{:?} not found", Self::CELL_NAME)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_opt(
|
||||||
|
db: &DBWithThreadMode<MultiThreaded>,
|
||||||
|
params: Self::KeyParams,
|
||||||
|
) -> DbResult<Option<Self>> {
|
||||||
|
let cf_ref = Self::column_ref(db);
|
||||||
|
let res = db
|
||||||
|
.get_cf(&cf_ref, Self::key_constructor(params)?)
|
||||||
|
.map_err(|rerr| {
|
||||||
|
DbError::rocksdb_cast_message(
|
||||||
|
rerr,
|
||||||
|
Some(format!("Failed to read {:?}", Self::CELL_NAME)),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
res.map(|data| {
|
||||||
|
borsh::from_slice::<Self>(&data).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some(format!("Failed to deserialize {:?}", Self::CELL_NAME)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.transpose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SimpleWritableCell: SimpleStorableCell + BorshSerialize {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>>;
|
||||||
|
|
||||||
|
fn put(&self, db: &DBWithThreadMode<MultiThreaded>, params: Self::KeyParams) -> DbResult<()> {
|
||||||
|
let cf_ref = Self::column_ref(db);
|
||||||
|
db.put_cf(
|
||||||
|
&cf_ref,
|
||||||
|
Self::key_constructor(params)?,
|
||||||
|
self.value_constructor()?,
|
||||||
|
)
|
||||||
|
.map_err(|rerr| {
|
||||||
|
DbError::rocksdb_cast_message(
|
||||||
|
rerr,
|
||||||
|
Some(format!("Failed to write {:?}", Self::CELL_NAME)),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_batch(
|
||||||
|
&self,
|
||||||
|
db: &DBWithThreadMode<MultiThreaded>,
|
||||||
|
params: Self::KeyParams,
|
||||||
|
write_batch: &mut WriteBatch,
|
||||||
|
) -> DbResult<()> {
|
||||||
|
let cf_ref = Self::column_ref(db);
|
||||||
|
write_batch.put_cf(
|
||||||
|
&cf_ref,
|
||||||
|
Self::key_constructor(params)?,
|
||||||
|
self.value_constructor()?,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
89
storage/src/cells/shared_cells.rs
Normal file
89
storage/src/cells/shared_cells.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use borsh::{BorshDeserialize, BorshSerialize};
|
||||||
|
use common::block::Block;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
BLOCK_CELL_NAME, CF_BLOCK_NAME, CF_META_NAME, DB_META_FIRST_BLOCK_IN_DB_KEY,
|
||||||
|
DB_META_FIRST_BLOCK_SET_KEY, DB_META_LAST_BLOCK_IN_DB_KEY, DbResult,
|
||||||
|
cells::{SimpleReadableCell, SimpleStorableCell, SimpleWritableCell},
|
||||||
|
error::DbError,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct LastBlockCell(pub u64);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for LastBlockCell {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_META_LAST_BLOCK_IN_DB_KEY;
|
||||||
|
const CF_NAME: &'static str = CF_META_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for LastBlockCell {}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for LastBlockCell {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize last block id".to_owned()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct FirstBlockSetCell(pub bool);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for FirstBlockSetCell {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_META_FIRST_BLOCK_SET_KEY;
|
||||||
|
const CF_NAME: &'static str = CF_META_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for FirstBlockSetCell {}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for FirstBlockSetCell {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize first block set flag".to_owned()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct FirstBlockCell(pub u64);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for FirstBlockCell {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_META_FIRST_BLOCK_IN_DB_KEY;
|
||||||
|
const CF_NAME: &'static str = CF_META_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for FirstBlockCell {}
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct BlockCell(pub Block);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for BlockCell {
|
||||||
|
type KeyParams = u64;
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = BLOCK_CELL_NAME;
|
||||||
|
const CF_NAME: &'static str = CF_BLOCK_NAME;
|
||||||
|
|
||||||
|
fn key_constructor(params: Self::KeyParams) -> DbResult<Vec<u8>> {
|
||||||
|
// ToDo: Replace with increasing ordering serialization
|
||||||
|
borsh::to_vec(¶ms).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some(format!(
|
||||||
|
"Failed to serialize {:?} key params",
|
||||||
|
Self::CELL_NAME
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for BlockCell {}
|
||||||
230
storage/src/indexer/indexer_cells.rs
Normal file
230
storage/src/indexer/indexer_cells.rs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
use borsh::{BorshDeserialize, BorshSerialize};
|
||||||
|
use nssa::V03State;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
CF_META_NAME, DbResult,
|
||||||
|
cells::{SimpleReadableCell, SimpleStorableCell, SimpleWritableCell},
|
||||||
|
error::DbError,
|
||||||
|
indexer::{
|
||||||
|
ACC_NUM_CELL_NAME, BLOCK_HASH_CELL_NAME, BREAKPOINT_CELL_NAME, CF_ACC_META,
|
||||||
|
CF_BREAKPOINT_NAME, CF_HASH_TO_ID, CF_TX_TO_ID, DB_META_LAST_BREAKPOINT_ID,
|
||||||
|
DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY, TX_HASH_CELL_NAME,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct LastObservedL1LibHeaderCell(pub [u8; 32]);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for LastObservedL1LibHeaderCell {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY;
|
||||||
|
const CF_NAME: &'static str = CF_META_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for LastObservedL1LibHeaderCell {}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for LastObservedL1LibHeaderCell {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize last observed l1 header".to_owned()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct LastBreakpointIdCell(pub u64);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for LastBreakpointIdCell {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_META_LAST_BREAKPOINT_ID;
|
||||||
|
const CF_NAME: &'static str = CF_META_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for LastBreakpointIdCell {}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for LastBreakpointIdCell {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize last breakpoint id".to_owned()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BorshDeserialize)]
|
||||||
|
pub struct BreakpointCellOwned(pub V03State);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for BreakpointCellOwned {
|
||||||
|
type KeyParams = u64;
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = BREAKPOINT_CELL_NAME;
|
||||||
|
const CF_NAME: &'static str = CF_BREAKPOINT_NAME;
|
||||||
|
|
||||||
|
fn key_constructor(params: Self::KeyParams) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(¶ms).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some(format!(
|
||||||
|
"Failed to serialize {:?} key params",
|
||||||
|
Self::CELL_NAME
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for BreakpointCellOwned {}
|
||||||
|
|
||||||
|
#[derive(BorshSerialize)]
|
||||||
|
pub struct BreakpointCellRef<'state>(pub &'state V03State);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for BreakpointCellRef<'_> {
|
||||||
|
type KeyParams = u64;
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = BREAKPOINT_CELL_NAME;
|
||||||
|
const CF_NAME: &'static str = CF_BREAKPOINT_NAME;
|
||||||
|
|
||||||
|
fn key_constructor(params: Self::KeyParams) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(¶ms).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some(format!(
|
||||||
|
"Failed to serialize {:?} key params",
|
||||||
|
Self::CELL_NAME
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for BreakpointCellRef<'_> {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize breakpoint".to_owned()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct BlockHashToBlockIdMapCell(pub u64);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for BlockHashToBlockIdMapCell {
|
||||||
|
type KeyParams = [u8; 32];
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = BLOCK_HASH_CELL_NAME;
|
||||||
|
const CF_NAME: &'static str = CF_HASH_TO_ID;
|
||||||
|
|
||||||
|
fn key_constructor(params: Self::KeyParams) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(¶ms).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some(format!(
|
||||||
|
"Failed to serialize {:?} key params",
|
||||||
|
Self::CELL_NAME
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for BlockHashToBlockIdMapCell {}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for BlockHashToBlockIdMapCell {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize block id".to_owned()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct TxHashToBlockIdMapCell(pub u64);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for TxHashToBlockIdMapCell {
|
||||||
|
type KeyParams = [u8; 32];
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = TX_HASH_CELL_NAME;
|
||||||
|
const CF_NAME: &'static str = CF_TX_TO_ID;
|
||||||
|
|
||||||
|
fn key_constructor(params: Self::KeyParams) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(¶ms).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some(format!(
|
||||||
|
"Failed to serialize {:?} key params",
|
||||||
|
Self::CELL_NAME
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for TxHashToBlockIdMapCell {}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for TxHashToBlockIdMapCell {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize block id".to_owned()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct AccNumTxCell(pub u64);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for AccNumTxCell {
|
||||||
|
type KeyParams = [u8; 32];
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = ACC_NUM_CELL_NAME;
|
||||||
|
const CF_NAME: &'static str = CF_ACC_META;
|
||||||
|
|
||||||
|
fn key_constructor(params: Self::KeyParams) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(¶ms).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some(format!(
|
||||||
|
"Failed to serialize {:?} key params",
|
||||||
|
Self::CELL_NAME
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for AccNumTxCell {}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for AccNumTxCell {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize number of transactions".to_owned()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod uniform_tests {
|
||||||
|
use crate::{
|
||||||
|
cells::SimpleStorableCell as _,
|
||||||
|
indexer::indexer_cells::{BreakpointCellOwned, BreakpointCellRef},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn breakpoint_ref_and_owned_is_aligned() {
|
||||||
|
assert_eq!(BreakpointCellRef::CELL_NAME, BreakpointCellOwned::CELL_NAME);
|
||||||
|
assert_eq!(BreakpointCellRef::CF_NAME, BreakpointCellOwned::CF_NAME);
|
||||||
|
assert_eq!(
|
||||||
|
BreakpointCellRef::key_constructor(1000).unwrap(),
|
||||||
|
BreakpointCellOwned::key_constructor(1000).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,44 +6,29 @@ use rocksdb::{
|
|||||||
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options,
|
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::error::DbError;
|
use crate::{BREAKPOINT_INTERVAL, CF_BLOCK_NAME, CF_META_NAME, DBIO, DbResult, error::DbError};
|
||||||
|
|
||||||
|
pub mod indexer_cells;
|
||||||
pub mod read_multiple;
|
pub mod read_multiple;
|
||||||
pub mod read_once;
|
pub mod read_once;
|
||||||
pub mod write_atomic;
|
pub mod write_atomic;
|
||||||
pub mod write_non_atomic;
|
pub mod write_non_atomic;
|
||||||
|
|
||||||
/// Maximal size of stored blocks in base.
|
|
||||||
///
|
|
||||||
/// Used to control db size.
|
|
||||||
///
|
|
||||||
/// Currently effectively unbounded.
|
|
||||||
pub const BUFF_SIZE_ROCKSDB: usize = usize::MAX;
|
|
||||||
|
|
||||||
/// Size of stored blocks cache in memory.
|
|
||||||
///
|
|
||||||
/// Keeping small to not run out of memory.
|
|
||||||
pub const CACHE_SIZE: usize = 1000;
|
|
||||||
|
|
||||||
/// Key base for storing metainformation about id of first block in db.
|
|
||||||
pub const DB_META_FIRST_BLOCK_IN_DB_KEY: &str = "first_block_in_db";
|
|
||||||
/// Key base for storing metainformation about id of last current block in db.
|
|
||||||
pub const DB_META_LAST_BLOCK_IN_DB_KEY: &str = "last_block_in_db";
|
|
||||||
/// Key base for storing metainformation about id of last observed L1 lib header in db.
|
/// Key base for storing metainformation about id of last observed L1 lib header in db.
|
||||||
pub const DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY: &str =
|
pub const DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY: &str =
|
||||||
"last_observed_l1_lib_header_in_db";
|
"last_observed_l1_lib_header_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 breakpoint.
|
/// Key base for storing metainformation about the last breakpoint.
|
||||||
pub const DB_META_LAST_BREAKPOINT_ID: &str = "last_breakpoint_id";
|
pub const DB_META_LAST_BREAKPOINT_ID: &str = "last_breakpoint_id";
|
||||||
|
|
||||||
/// Interval between state breakpoints.
|
/// Cell name for a breakpoint.
|
||||||
pub const BREAKPOINT_INTERVAL: u8 = 100;
|
pub const BREAKPOINT_CELL_NAME: &str = "breakpoint";
|
||||||
|
/// Cell name for a block hash to block id map.
|
||||||
|
pub const BLOCK_HASH_CELL_NAME: &str = "block hash";
|
||||||
|
/// Cell name for a tx hash to block id map.
|
||||||
|
pub const TX_HASH_CELL_NAME: &str = "tx hash";
|
||||||
|
/// Cell name for a account number of transactions.
|
||||||
|
pub const ACC_NUM_CELL_NAME: &str = "acc id";
|
||||||
|
|
||||||
/// Name of block column family.
|
|
||||||
pub const CF_BLOCK_NAME: &str = "cf_block";
|
|
||||||
/// Name of meta column family.
|
|
||||||
pub const CF_META_NAME: &str = "cf_meta";
|
|
||||||
/// Name of breakpoint column family.
|
/// Name of breakpoint column family.
|
||||||
pub const CF_BREAKPOINT_NAME: &str = "cf_breakpoint";
|
pub const CF_BREAKPOINT_NAME: &str = "cf_breakpoint";
|
||||||
/// Name of hash to id map column family.
|
/// Name of hash to id map column family.
|
||||||
@ -55,12 +40,16 @@ pub const CF_ACC_META: &str = "cf_acc_meta";
|
|||||||
/// Name of account id to tx hash map column family.
|
/// Name of account id to tx hash map column family.
|
||||||
pub const CF_ACC_TO_TX: &str = "cf_acc_to_tx";
|
pub const CF_ACC_TO_TX: &str = "cf_acc_to_tx";
|
||||||
|
|
||||||
pub type DbResult<T> = Result<T, DbError>;
|
|
||||||
|
|
||||||
pub struct RocksDBIO {
|
pub struct RocksDBIO {
|
||||||
pub db: DBWithThreadMode<MultiThreaded>,
|
pub db: DBWithThreadMode<MultiThreaded>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DBIO for RocksDBIO {
|
||||||
|
fn db(&self) -> &DBWithThreadMode<MultiThreaded> {
|
||||||
|
&self.db
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RocksDBIO {
|
impl RocksDBIO {
|
||||||
pub fn open_or_create(
|
pub fn open_or_create(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
use super::{
|
use super::{Block, DbResult, RocksDBIO, V03State};
|
||||||
Block, DB_META_FIRST_BLOCK_IN_DB_KEY, DB_META_FIRST_BLOCK_SET_KEY,
|
use crate::{
|
||||||
DB_META_LAST_BLOCK_IN_DB_KEY, DB_META_LAST_BREAKPOINT_ID,
|
DBIO as _,
|
||||||
DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY, DbError, DbResult, RocksDBIO, V03State,
|
cells::shared_cells::{BlockCell, FirstBlockCell, FirstBlockSetCell, LastBlockCell},
|
||||||
|
indexer::indexer_cells::{
|
||||||
|
AccNumTxCell, BlockHashToBlockIdMapCell, BreakpointCellOwned, LastBreakpointIdCell,
|
||||||
|
LastObservedL1LibHeaderCell, TxHashToBlockIdMapCell,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[expect(clippy::multiple_inherent_impl, reason = "Readability")]
|
#[expect(clippy::multiple_inherent_impl, reason = "Readability")]
|
||||||
@ -9,264 +13,55 @@ impl RocksDBIO {
|
|||||||
// Meta
|
// Meta
|
||||||
|
|
||||||
pub fn get_meta_first_block_in_db(&self) -> DbResult<u64> {
|
pub fn get_meta_first_block_in_db(&self) -> DbResult<u64> {
|
||||||
let cf_meta = self.meta_column();
|
self.get::<FirstBlockCell>(()).map(|cell| cell.0)
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_FIRST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_FIRST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(borsh::from_slice::<u64>(&data).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to deserialize first block".to_owned()),
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"First block not found".to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_meta_last_block_in_db(&self) -> DbResult<u64> {
|
pub fn get_meta_last_block_in_db(&self) -> DbResult<u64> {
|
||||||
let cf_meta = self.meta_column();
|
self.get::<LastBlockCell>(()).map(|cell| cell.0)
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(borsh::from_slice::<u64>(&data).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to deserialize last block".to_owned()),
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Last block not found".to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_meta_last_observed_l1_lib_header_in_db(&self) -> DbResult<Option<[u8; 32]>> {
|
pub fn get_meta_last_observed_l1_lib_header_in_db(&self) -> DbResult<Option<[u8; 32]>> {
|
||||||
let cf_meta = self.meta_column();
|
self.get_opt::<LastObservedL1LibHeaderCell>(())
|
||||||
let res = self
|
.map(|opt| opt.map(|val| val.0))
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY).map_err(
|
|
||||||
|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some(
|
|
||||||
"Failed to serialize DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY"
|
|
||||||
.to_owned(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
res.map(|data| {
|
|
||||||
borsh::from_slice::<[u8; 32]>(&data).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to deserialize last l1 lib header".to_owned()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.transpose()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_meta_is_first_block_set(&self) -> DbResult<bool> {
|
pub fn get_meta_is_first_block_set(&self) -> DbResult<bool> {
|
||||||
let cf_meta = self.meta_column();
|
Ok(self.get_opt::<FirstBlockSetCell>(())?.is_some())
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
Ok(res.is_some())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_meta_last_breakpoint_id(&self) -> DbResult<u64> {
|
pub fn get_meta_last_breakpoint_id(&self) -> DbResult<u64> {
|
||||||
let cf_meta = self.meta_column();
|
self.get::<LastBreakpointIdCell>(()).map(|cell| cell.0)
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BREAKPOINT_ID).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BREAKPOINT_ID".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(borsh::from_slice::<u64>(&data).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to deserialize last breakpoint id".to_owned()),
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Last breakpoint id not found".to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block
|
// Block
|
||||||
|
|
||||||
pub fn get_block(&self, block_id: u64) -> DbResult<Option<Block>> {
|
pub fn get_block(&self, block_id: u64) -> DbResult<Option<Block>> {
|
||||||
let cf_block = self.block_column();
|
self.get_opt::<BlockCell>(block_id)
|
||||||
let res = self
|
.map(|opt| opt.map(|val| val.0))
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_block,
|
|
||||||
borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(Some(borsh::from_slice::<Block>(&data).map_err(|serr| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
serr,
|
|
||||||
Some("Failed to deserialize block data".to_owned()),
|
|
||||||
)
|
|
||||||
})?))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
pub fn get_breakpoint(&self, br_id: u64) -> DbResult<V03State> {
|
pub fn get_breakpoint(&self, br_id: u64) -> DbResult<V03State> {
|
||||||
let cf_br = self.breakpoint_column();
|
self.get::<BreakpointCellOwned>(br_id).map(|cell| cell.0)
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_br,
|
|
||||||
borsh::to_vec(&br_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize breakpoint id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(borsh::from_slice::<V03State>(&data).map_err(|serr| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
serr,
|
|
||||||
Some("Failed to deserialize breakpoint data".to_owned()),
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Breakpoint on this id not found".to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mappings
|
// Mappings
|
||||||
|
|
||||||
pub fn get_block_id_by_hash(&self, hash: [u8; 32]) -> DbResult<Option<u64>> {
|
pub fn get_block_id_by_hash(&self, hash: [u8; 32]) -> DbResult<Option<u64>> {
|
||||||
let cf_hti = self.hash_to_id_column();
|
self.get_opt::<BlockHashToBlockIdMapCell>(hash)
|
||||||
let res = self
|
.map(|opt| opt.map(|cell| cell.0))
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_hti,
|
|
||||||
borsh::to_vec(&hash).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize block hash".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(Some(borsh::from_slice::<u64>(&data).map_err(|serr| {
|
|
||||||
DbError::borsh_cast_message(serr, Some("Failed to deserialize block id".to_owned()))
|
|
||||||
})?))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block_id_by_tx_hash(&self, tx_hash: [u8; 32]) -> DbResult<Option<u64>> {
|
pub fn get_block_id_by_tx_hash(&self, tx_hash: [u8; 32]) -> DbResult<Option<u64>> {
|
||||||
let cf_tti = self.tx_hash_to_id_column();
|
self.get_opt::<TxHashToBlockIdMapCell>(tx_hash)
|
||||||
let res = self
|
.map(|opt| opt.map(|cell| cell.0))
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_tti,
|
|
||||||
borsh::to_vec(&tx_hash).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize transaction hash".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(Some(borsh::from_slice::<u64>(&data).map_err(|serr| {
|
|
||||||
DbError::borsh_cast_message(serr, Some("Failed to deserialize block id".to_owned()))
|
|
||||||
})?))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accounts meta
|
// Accounts meta
|
||||||
|
|
||||||
pub(crate) fn get_acc_meta_num_tx(&self, acc_id: [u8; 32]) -> DbResult<Option<u64>> {
|
pub(crate) fn get_acc_meta_num_tx(&self, acc_id: [u8; 32]) -> DbResult<Option<u64>> {
|
||||||
let cf_ameta = self.account_meta_column();
|
self.get_opt::<AccNumTxCell>(acc_id)
|
||||||
let res = self.db.get_cf(&cf_ameta, acc_id).map_err(|rerr| {
|
.map(|opt| opt.map(|cell| cell.0))
|
||||||
DbError::rocksdb_cast_message(rerr, Some("Failed to read from acc meta cf".to_owned()))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
res.map(|data| {
|
|
||||||
borsh::from_slice::<u64>(&data).map_err(|serr| {
|
|
||||||
DbError::borsh_cast_message(serr, Some("Failed to deserialize num tx".to_owned()))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.transpose()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,14 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use rocksdb::WriteBatch;
|
use rocksdb::WriteBatch;
|
||||||
|
|
||||||
use super::{
|
use super::{BREAKPOINT_INTERVAL, Block, DbError, DbResult, RocksDBIO};
|
||||||
Arc, BREAKPOINT_INTERVAL, Block, BoundColumnFamily, DB_META_FIRST_BLOCK_IN_DB_KEY,
|
use crate::{
|
||||||
DB_META_FIRST_BLOCK_SET_KEY, DB_META_LAST_BLOCK_IN_DB_KEY, DB_META_LAST_BREAKPOINT_ID,
|
DB_META_FIRST_BLOCK_IN_DB_KEY, DBIO as _,
|
||||||
DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY, DbError, DbResult, RocksDBIO,
|
cells::shared_cells::{FirstBlockSetCell, LastBlockCell},
|
||||||
|
indexer::indexer_cells::{
|
||||||
|
AccNumTxCell, BlockHashToBlockIdMapCell, LastBreakpointIdCell, LastObservedL1LibHeaderCell,
|
||||||
|
TxHashToBlockIdMapCell,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[expect(clippy::multiple_inherent_impl, reason = "Readability")]
|
#[expect(clippy::multiple_inherent_impl, reason = "Readability")]
|
||||||
@ -18,22 +22,27 @@ impl RocksDBIO {
|
|||||||
num_tx: u64,
|
num_tx: u64,
|
||||||
write_batch: &mut WriteBatch,
|
write_batch: &mut WriteBatch,
|
||||||
) -> DbResult<()> {
|
) -> DbResult<()> {
|
||||||
let cf_ameta = self.account_meta_column();
|
self.put_batch(&AccNumTxCell(num_tx), acc_id, write_batch)
|
||||||
|
}
|
||||||
|
|
||||||
write_batch.put_cf(
|
// Mappings
|
||||||
&cf_ameta,
|
|
||||||
borsh::to_vec(&acc_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(err, Some("Failed to serialize account id".to_owned()))
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&num_tx).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize acc metadata".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
pub fn put_block_id_by_hash_batch(
|
||||||
|
&self,
|
||||||
|
hash: [u8; 32],
|
||||||
|
block_id: u64,
|
||||||
|
write_batch: &mut WriteBatch,
|
||||||
|
) -> DbResult<()> {
|
||||||
|
self.put_batch(&BlockHashToBlockIdMapCell(block_id), hash, write_batch)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_block_id_by_tx_hash_batch(
|
||||||
|
&self,
|
||||||
|
tx_hash: [u8; 32],
|
||||||
|
block_id: u64,
|
||||||
|
write_batch: &mut WriteBatch,
|
||||||
|
) -> DbResult<()> {
|
||||||
|
self.put_batch(&TxHashToBlockIdMapCell(block_id), tx_hash, write_batch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account
|
// Account
|
||||||
@ -163,23 +172,7 @@ impl RocksDBIO {
|
|||||||
block_id: u64,
|
block_id: u64,
|
||||||
write_batch: &mut WriteBatch,
|
write_batch: &mut WriteBatch,
|
||||||
) -> DbResult<()> {
|
) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
self.put_batch(&LastBlockCell(block_id), (), write_batch)
|
||||||
write_batch.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_meta_last_observed_l1_lib_header_in_db_batch(
|
pub fn put_meta_last_observed_l1_lib_header_in_db_batch(
|
||||||
@ -187,26 +180,7 @@ impl RocksDBIO {
|
|||||||
l1_lib_header: [u8; 32],
|
l1_lib_header: [u8; 32],
|
||||||
write_batch: &mut WriteBatch,
|
write_batch: &mut WriteBatch,
|
||||||
) -> DbResult<()> {
|
) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
self.put_batch(&LastObservedL1LibHeaderCell(l1_lib_header), (), write_batch)
|
||||||
write_batch.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some(
|
|
||||||
"Failed to serialize DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY"
|
|
||||||
.to_owned(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&l1_lib_header).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last l1 block header".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_meta_last_breakpoint_id_batch(
|
pub fn put_meta_last_breakpoint_id_batch(
|
||||||
@ -214,46 +188,17 @@ impl RocksDBIO {
|
|||||||
br_id: u64,
|
br_id: u64,
|
||||||
write_batch: &mut WriteBatch,
|
write_batch: &mut WriteBatch,
|
||||||
) -> DbResult<()> {
|
) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
self.put_batch(&LastBreakpointIdCell(br_id), (), write_batch)
|
||||||
write_batch.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BREAKPOINT_ID).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BREAKPOINT_ID".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&br_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_meta_is_first_block_set_batch(&self, write_batch: &mut WriteBatch) -> DbResult<()> {
|
pub fn put_meta_is_first_block_set_batch(&self, write_batch: &mut WriteBatch) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
self.put_batch(&FirstBlockSetCell(true), (), write_batch)
|
||||||
write_batch.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
[1_u8; 1],
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block
|
// Block
|
||||||
|
|
||||||
pub fn put_block(&self, block: &Block, l1_lib_header: [u8; 32]) -> DbResult<()> {
|
pub fn put_block(&self, block: &Block, l1_lib_header: [u8; 32]) -> DbResult<()> {
|
||||||
let cf_block = self.block_column();
|
let cf_block = self.block_column();
|
||||||
let cf_hti = self.hash_to_id_column();
|
|
||||||
let cf_tti: Arc<BoundColumnFamily<'_>> = self.tx_hash_to_id_column();
|
|
||||||
let last_curr_block = self.get_meta_last_block_in_db()?;
|
let last_curr_block = self.get_meta_last_block_in_db()?;
|
||||||
let mut write_batch = WriteBatch::default();
|
let mut write_batch = WriteBatch::default();
|
||||||
|
|
||||||
@ -272,33 +217,22 @@ impl RocksDBIO {
|
|||||||
self.put_meta_last_observed_l1_lib_header_in_db_batch(l1_lib_header, &mut write_batch)?;
|
self.put_meta_last_observed_l1_lib_header_in_db_batch(l1_lib_header, &mut write_batch)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_batch.put_cf(
|
self.put_block_id_by_hash_batch(
|
||||||
&cf_hti,
|
block.header.hash.into(),
|
||||||
borsh::to_vec(&block.header.hash).map_err(|err| {
|
block.header.block_id,
|
||||||
DbError::borsh_cast_message(err, Some("Failed to serialize block hash".to_owned()))
|
&mut write_batch,
|
||||||
})?,
|
)?;
|
||||||
borsh::to_vec(&block.header.block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(err, Some("Failed to serialize block id".to_owned()))
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut acc_to_tx_map: HashMap<[u8; 32], Vec<[u8; 32]>> = HashMap::new();
|
let mut acc_to_tx_map: HashMap<[u8; 32], Vec<[u8; 32]>> = HashMap::new();
|
||||||
|
|
||||||
for tx in &block.body.transactions {
|
for tx in &block.body.transactions {
|
||||||
let tx_hash = tx.hash();
|
let tx_hash = tx.hash();
|
||||||
|
|
||||||
write_batch.put_cf(
|
self.put_block_id_by_tx_hash_batch(
|
||||||
&cf_tti,
|
tx_hash.into(),
|
||||||
borsh::to_vec(&tx_hash).map_err(|err| {
|
block.header.block_id,
|
||||||
DbError::borsh_cast_message(err, Some("Failed to serialize tx hash".to_owned()))
|
&mut write_batch,
|
||||||
})?,
|
)?;
|
||||||
borsh::to_vec(&block.header.block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
|
|
||||||
let acc_ids = tx
|
let acc_ids = tx
|
||||||
.affected_public_account_ids()
|
.affected_public_account_ids()
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
use super::{
|
use super::{BREAKPOINT_INTERVAL, DbError, DbResult, RocksDBIO, V03State};
|
||||||
BREAKPOINT_INTERVAL, DB_META_FIRST_BLOCK_SET_KEY, DB_META_LAST_BLOCK_IN_DB_KEY,
|
use crate::{
|
||||||
DB_META_LAST_BREAKPOINT_ID, DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY, DbError,
|
DBIO as _,
|
||||||
DbResult, RocksDBIO, V03State,
|
cells::shared_cells::{FirstBlockSetCell, LastBlockCell},
|
||||||
|
indexer::indexer_cells::{
|
||||||
|
BreakpointCellRef, LastBreakpointIdCell, LastObservedL1LibHeaderCell,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[expect(clippy::multiple_inherent_impl, reason = "Readability")]
|
#[expect(clippy::multiple_inherent_impl, reason = "Readability")]
|
||||||
@ -9,118 +12,28 @@ impl RocksDBIO {
|
|||||||
// Meta
|
// Meta
|
||||||
|
|
||||||
pub fn put_meta_last_block_in_db(&self, block_id: u64) -> DbResult<()> {
|
pub fn put_meta_last_block_in_db(&self, block_id: u64) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
self.put(&LastBlockCell(block_id), ())
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_meta_last_observed_l1_lib_header_in_db(
|
pub fn put_meta_last_observed_l1_lib_header_in_db(
|
||||||
&self,
|
&self,
|
||||||
l1_lib_header: [u8; 32],
|
l1_lib_header: [u8; 32],
|
||||||
) -> DbResult<()> {
|
) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
self.put(&LastObservedL1LibHeaderCell(l1_lib_header), ())
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY).map_err(
|
|
||||||
|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some(
|
|
||||||
"Failed to serialize DB_META_LAST_OBSERVED_L1_LIB_HEADER_ID_IN_DB_KEY"
|
|
||||||
.to_owned(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)?,
|
|
||||||
borsh::to_vec(&l1_lib_header).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last l1 block header".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_meta_last_breakpoint_id(&self, br_id: u64) -> DbResult<()> {
|
pub fn put_meta_last_breakpoint_id(&self, br_id: u64) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
self.put(&LastBreakpointIdCell(br_id), ())
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BREAKPOINT_ID).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BREAKPOINT_ID".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&br_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_meta_is_first_block_set(&self) -> DbResult<()> {
|
pub fn put_meta_is_first_block_set(&self) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
self.put(&FirstBlockSetCell(true), ())
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
[1_u8; 1],
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
pub fn put_breakpoint(&self, br_id: u64, breakpoint: &V03State) -> DbResult<()> {
|
pub fn put_breakpoint(&self, br_id: u64, breakpoint: &V03State) -> DbResult<()> {
|
||||||
let cf_br = self.breakpoint_column();
|
self.put(&BreakpointCellRef(breakpoint), br_id)
|
||||||
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_br,
|
|
||||||
borsh::to_vec(&br_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize breakpoint id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(breakpoint).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize breakpoint data".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_next_breakpoint(&self) -> DbResult<()> {
|
pub fn put_next_breakpoint(&self) -> DbResult<()> {
|
||||||
|
|||||||
@ -1,3 +1,69 @@
|
|||||||
|
use rocksdb::{DBWithThreadMode, MultiThreaded, WriteBatch};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
cells::{SimpleReadableCell, SimpleWritableCell},
|
||||||
|
error::DbError,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod cells;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod indexer;
|
pub mod indexer;
|
||||||
pub mod sequencer;
|
pub mod sequencer;
|
||||||
|
|
||||||
|
/// Maximal size of stored blocks in base.
|
||||||
|
///
|
||||||
|
/// Used to control db size.
|
||||||
|
///
|
||||||
|
/// Currently effectively unbounded.
|
||||||
|
pub const BUFF_SIZE_ROCKSDB: usize = usize::MAX;
|
||||||
|
|
||||||
|
/// Size of stored blocks cache in memory.
|
||||||
|
///
|
||||||
|
/// Keeping small to not run out of memory.
|
||||||
|
pub const CACHE_SIZE: usize = 1000;
|
||||||
|
|
||||||
|
/// 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 id of first block in db.
|
||||||
|
pub const DB_META_FIRST_BLOCK_IN_DB_KEY: &str = "first_block_in_db";
|
||||||
|
/// Key base for storing metainformation about id of last current block in db.
|
||||||
|
pub const DB_META_LAST_BLOCK_IN_DB_KEY: &str = "last_block_in_db";
|
||||||
|
|
||||||
|
/// Cell name for a block.
|
||||||
|
pub const BLOCK_CELL_NAME: &str = "block";
|
||||||
|
|
||||||
|
/// Interval between state breakpoints.
|
||||||
|
pub const BREAKPOINT_INTERVAL: u8 = 100;
|
||||||
|
|
||||||
|
/// Name of block column family.
|
||||||
|
pub const CF_BLOCK_NAME: &str = "cf_block";
|
||||||
|
/// Name of meta column family.
|
||||||
|
pub const CF_META_NAME: &str = "cf_meta";
|
||||||
|
|
||||||
|
pub type DbResult<T> = Result<T, DbError>;
|
||||||
|
|
||||||
|
/// Minimal requirements for DB IO.
|
||||||
|
pub trait DBIO {
|
||||||
|
fn db(&self) -> &DBWithThreadMode<MultiThreaded>;
|
||||||
|
|
||||||
|
fn get<T: SimpleReadableCell>(&self, params: T::KeyParams) -> DbResult<T> {
|
||||||
|
T::get(self.db(), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_opt<T: SimpleReadableCell>(&self, params: T::KeyParams) -> DbResult<Option<T>> {
|
||||||
|
T::get_opt(self.db(), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put<T: SimpleWritableCell>(&self, cell: &T, params: T::KeyParams) -> DbResult<()> {
|
||||||
|
cell.put(self.db(), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_batch<T: SimpleWritableCell>(
|
||||||
|
&self,
|
||||||
|
cell: &T,
|
||||||
|
params: T::KeyParams,
|
||||||
|
write_batch: &mut WriteBatch,
|
||||||
|
) -> DbResult<()> {
|
||||||
|
cell.put_batch(self.db(), params, write_batch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,596 +0,0 @@
|
|||||||
use std::{path::Path, sync::Arc};
|
|
||||||
|
|
||||||
use common::block::{BedrockStatus, Block, BlockMeta, MantleMsgId};
|
|
||||||
use nssa::V03State;
|
|
||||||
use rocksdb::{
|
|
||||||
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options, WriteBatch,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::error::DbError;
|
|
||||||
|
|
||||||
/// Maximal size of stored blocks in base.
|
|
||||||
///
|
|
||||||
/// Used to control db size.
|
|
||||||
///
|
|
||||||
/// Currently effectively unbounded.
|
|
||||||
pub const BUFF_SIZE_ROCKSDB: usize = usize::MAX;
|
|
||||||
|
|
||||||
/// Size of stored blocks cache in memory.
|
|
||||||
///
|
|
||||||
/// Keeping small to not run out of memory.
|
|
||||||
pub const CACHE_SIZE: usize = 1000;
|
|
||||||
|
|
||||||
/// Key base for storing metainformation about id of first block in db.
|
|
||||||
pub const DB_META_FIRST_BLOCK_IN_DB_KEY: &str = "first_block_in_db";
|
|
||||||
/// Key base for storing metainformation about id of last current 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 metainformation about the latest block meta.
|
|
||||||
pub const DB_META_LATEST_BLOCK_META_KEY: &str = "latest_block_meta";
|
|
||||||
|
|
||||||
/// Key base for storing the NSSA state.
|
|
||||||
pub const DB_NSSA_STATE_KEY: &str = "nssa_state";
|
|
||||||
|
|
||||||
/// Name of block column family.
|
|
||||||
pub const CF_BLOCK_NAME: &str = "cf_block";
|
|
||||||
/// Name of meta column family.
|
|
||||||
pub const CF_META_NAME: &str = "cf_meta";
|
|
||||||
/// Name of state column family.
|
|
||||||
pub const CF_NSSA_STATE_NAME: &str = "cf_nssa_state";
|
|
||||||
|
|
||||||
pub type DbResult<T> = Result<T, DbError>;
|
|
||||||
|
|
||||||
pub struct RocksDBIO {
|
|
||||||
pub db: DBWithThreadMode<MultiThreaded>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RocksDBIO {
|
|
||||||
pub fn open_or_create(
|
|
||||||
path: &Path,
|
|
||||||
genesis_block: &Block,
|
|
||||||
genesis_msg_id: MantleMsgId,
|
|
||||||
) -> DbResult<Self> {
|
|
||||||
let mut cf_opts = Options::default();
|
|
||||||
cf_opts.set_max_write_buffer_number(16);
|
|
||||||
// ToDo: Add more column families for different data
|
|
||||||
let cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone());
|
|
||||||
let cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone());
|
|
||||||
let cfstate = ColumnFamilyDescriptor::new(CF_NSSA_STATE_NAME, cf_opts.clone());
|
|
||||||
|
|
||||||
let mut db_opts = Options::default();
|
|
||||||
db_opts.create_missing_column_families(true);
|
|
||||||
db_opts.create_if_missing(true);
|
|
||||||
let db = DBWithThreadMode::<MultiThreaded>::open_cf_descriptors(
|
|
||||||
&db_opts,
|
|
||||||
path,
|
|
||||||
vec![cfb, cfmeta, cfstate],
|
|
||||||
)
|
|
||||||
.map_err(|err| DbError::RocksDbError {
|
|
||||||
error: err,
|
|
||||||
additional_info: Some("Failed to open or create DB".to_owned()),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let dbio = Self { db };
|
|
||||||
|
|
||||||
let is_start_set = dbio.get_meta_is_first_block_set()?;
|
|
||||||
if !is_start_set {
|
|
||||||
let block_id = genesis_block.header.block_id;
|
|
||||||
dbio.put_meta_first_block_in_db(genesis_block, genesis_msg_id)?;
|
|
||||||
dbio.put_meta_is_first_block_set()?;
|
|
||||||
dbio.put_meta_last_block_in_db(block_id)?;
|
|
||||||
dbio.put_meta_last_finalized_block_id(None)?;
|
|
||||||
dbio.put_meta_latest_block_meta(&BlockMeta {
|
|
||||||
id: genesis_block.header.block_id,
|
|
||||||
hash: genesis_block.header.hash,
|
|
||||||
msg_id: genesis_msg_id,
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(dbio)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destroy(path: &Path) -> DbResult<()> {
|
|
||||||
let mut cf_opts = Options::default();
|
|
||||||
cf_opts.set_max_write_buffer_number(16);
|
|
||||||
// ToDo: Add more column families for different data
|
|
||||||
let _cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone());
|
|
||||||
let _cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone());
|
|
||||||
let _cfstate = ColumnFamilyDescriptor::new(CF_NSSA_STATE_NAME, cf_opts.clone());
|
|
||||||
|
|
||||||
let mut db_opts = Options::default();
|
|
||||||
db_opts.create_missing_column_families(true);
|
|
||||||
db_opts.create_if_missing(true);
|
|
||||||
DBWithThreadMode::<MultiThreaded>::destroy(&db_opts, path)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn meta_column(&self) -> Arc<BoundColumnFamily<'_>> {
|
|
||||||
self.db.cf_handle(CF_META_NAME).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn block_column(&self) -> Arc<BoundColumnFamily<'_>> {
|
|
||||||
self.db.cf_handle(CF_BLOCK_NAME).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nssa_state_column(&self) -> Arc<BoundColumnFamily<'_>> {
|
|
||||||
self.db.cf_handle(CF_NSSA_STATE_NAME).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_meta_first_block_in_db(&self) -> DbResult<u64> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_FIRST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_FIRST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(borsh::from_slice::<u64>(&data).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to deserialize first block".to_owned()),
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"First block not found".to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_meta_last_block_in_db(&self) -> DbResult<u64> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(borsh::from_slice::<u64>(&data).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to deserialize last block".to_owned()),
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Last block not found".to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_meta_is_first_block_set(&self) -> DbResult<bool> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
Ok(res.is_some())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_nssa_state_in_db(&self, state: &V03State, batch: &mut WriteBatch) -> DbResult<()> {
|
|
||||||
let cf_nssa_state = self.nssa_state_column();
|
|
||||||
batch.put_cf(
|
|
||||||
&cf_nssa_state,
|
|
||||||
borsh::to_vec(&DB_NSSA_STATE_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_NSSA_STATE_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(state).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(err, Some("Failed to serialize NSSA state".to_owned()))
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_meta_first_block_in_db(&self, block: &Block, msg_id: MantleMsgId) -> DbResult<()> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_FIRST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_FIRST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block.header.block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize first block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
let mut batch = WriteBatch::default();
|
|
||||||
self.put_block(block, msg_id, true, &mut batch)?;
|
|
||||||
self.db.write(batch).map_err(|rerr| {
|
|
||||||
DbError::rocksdb_cast_message(
|
|
||||||
rerr,
|
|
||||||
Some("Failed to write first block in db".to_owned()),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_meta_last_block_in_db(&self, block_id: u64) -> DbResult<()> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_meta_last_block_in_db_batch(
|
|
||||||
&self,
|
|
||||||
block_id: u64,
|
|
||||||
batch: &mut WriteBatch,
|
|
||||||
) -> DbResult<()> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
batch.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_meta_last_finalized_block_id(&self, block_id: Option<u64>) -> 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_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize last block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.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
|
|
||||||
.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
[1_u8; 1],
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_meta_latest_block_meta(&self, block_meta: &BlockMeta) -> DbResult<()> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LATEST_BLOCK_META_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LATEST_BLOCK_META_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block_meta).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize latest block meta".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_meta_latest_block_meta_batch(
|
|
||||||
&self,
|
|
||||||
block_meta: &BlockMeta,
|
|
||||||
batch: &mut WriteBatch,
|
|
||||||
) -> DbResult<()> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
batch.put_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LATEST_BLOCK_META_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LATEST_BLOCK_META_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block_meta).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize latest block meta".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn latest_block_meta(&self) -> DbResult<BlockMeta> {
|
|
||||||
let cf_meta = self.meta_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_meta,
|
|
||||||
borsh::to_vec(&DB_META_LATEST_BLOCK_META_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize DB_META_LATEST_BLOCK_META_KEY".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(borsh::from_slice::<BlockMeta>(&data).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to deserialize latest block meta".to_owned()),
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Latest block meta not found".to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_block(
|
|
||||||
&self,
|
|
||||||
block: &Block,
|
|
||||||
msg_id: MantleMsgId,
|
|
||||||
first: bool,
|
|
||||||
batch: &mut WriteBatch,
|
|
||||||
) -> DbResult<()> {
|
|
||||||
let cf_block = self.block_column();
|
|
||||||
|
|
||||||
if !first {
|
|
||||||
let last_curr_block = self.get_meta_last_block_in_db()?;
|
|
||||||
|
|
||||||
if block.header.block_id > last_curr_block {
|
|
||||||
self.put_meta_last_block_in_db_batch(block.header.block_id, batch)?;
|
|
||||||
self.put_meta_latest_block_meta_batch(
|
|
||||||
&BlockMeta {
|
|
||||||
id: block.header.block_id,
|
|
||||||
hash: block.header.hash,
|
|
||||||
msg_id,
|
|
||||||
},
|
|
||||||
batch,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
batch.put_cf(
|
|
||||||
&cf_block,
|
|
||||||
borsh::to_vec(&block.header.block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(err, Some("Failed to serialize block id".to_owned()))
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(block).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(err, Some("Failed to serialize block data".to_owned()))
|
|
||||||
})?,
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_block(&self, block_id: u64) -> DbResult<Option<Block>> {
|
|
||||||
let cf_block = self.block_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_block,
|
|
||||||
borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(Some(borsh::from_slice::<Block>(&data).map_err(|serr| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
serr,
|
|
||||||
Some("Failed to deserialize block data".to_owned()),
|
|
||||||
)
|
|
||||||
})?))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_nssa_state(&self) -> DbResult<V03State> {
|
|
||||||
let cf_nssa_state = self.nssa_state_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(
|
|
||||||
&cf_nssa_state,
|
|
||||||
borsh::to_vec(&DB_NSSA_STATE_KEY).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(borsh::from_slice::<V03State>(&data).map_err(|serr| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
serr,
|
|
||||||
Some("Failed to deserialize block data".to_owned()),
|
|
||||||
)
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"NSSA state not found".to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn delete_block(&self, block_id: u64) -> DbResult<()> {
|
|
||||||
let cf_block = self.block_column();
|
|
||||||
let key = borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(err, Some("Failed to serialize block id".to_owned()))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if self
|
|
||||||
.db
|
|
||||||
.get_cf(&cf_block, &key)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
return Err(DbError::db_interaction_error(format!(
|
|
||||||
"Block with id {block_id} not found"
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.db
|
|
||||||
.delete_cf(&cf_block, key)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mark_block_as_finalized(&self, block_id: u64) -> DbResult<()> {
|
|
||||||
let mut block = self.get_block(block_id)?.ok_or_else(|| {
|
|
||||||
DbError::db_interaction_error(format!("Block with id {block_id} not found"))
|
|
||||||
})?;
|
|
||||||
block.bedrock_status = BedrockStatus::Finalized;
|
|
||||||
|
|
||||||
let cf_block = self.block_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_block,
|
|
||||||
borsh::to_vec(&block_id).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize block id".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
borsh::to_vec(&block).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to serialize block data".to_owned()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| {
|
|
||||||
DbError::rocksdb_cast_message(
|
|
||||||
rerr,
|
|
||||||
Some(format!("Failed to mark block {block_id} as finalized")),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_all_blocks(&self) -> impl Iterator<Item = DbResult<Block>> {
|
|
||||||
let cf_block = self.block_column();
|
|
||||||
self.db
|
|
||||||
.iterator_cf(&cf_block, rocksdb::IteratorMode::Start)
|
|
||||||
.map(|res| {
|
|
||||||
let (_key, value) = res.map_err(|rerr| {
|
|
||||||
DbError::rocksdb_cast_message(
|
|
||||||
rerr,
|
|
||||||
Some("Failed to get key value pair".to_owned()),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
borsh::from_slice::<Block>(&value).map_err(|err| {
|
|
||||||
DbError::borsh_cast_message(
|
|
||||||
err,
|
|
||||||
Some("Failed to deserialize block data".to_owned()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn atomic_update(
|
|
||||||
&self,
|
|
||||||
block: &Block,
|
|
||||||
msg_id: MantleMsgId,
|
|
||||||
state: &V03State,
|
|
||||||
) -> DbResult<()> {
|
|
||||||
let block_id = block.header.block_id;
|
|
||||||
let mut batch = WriteBatch::default();
|
|
||||||
self.put_block(block, msg_id, false, &mut batch)?;
|
|
||||||
self.put_nssa_state_in_db(state, &mut batch)?;
|
|
||||||
self.db.write(batch).map_err(|rerr| {
|
|
||||||
DbError::rocksdb_cast_message(
|
|
||||||
rerr,
|
|
||||||
Some(format!("Failed to udpate db with block {block_id}")),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
349
storage/src/sequencer/mod.rs
Normal file
349
storage/src/sequencer/mod.rs
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
|
use common::block::{BedrockStatus, Block, BlockMeta, MantleMsgId};
|
||||||
|
use nssa::V03State;
|
||||||
|
use rocksdb::{
|
||||||
|
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options, WriteBatch,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
CF_BLOCK_NAME, CF_META_NAME, DB_META_FIRST_BLOCK_IN_DB_KEY, DBIO, DbResult,
|
||||||
|
cells::shared_cells::{BlockCell, FirstBlockCell, FirstBlockSetCell, LastBlockCell},
|
||||||
|
error::DbError,
|
||||||
|
sequencer::sequencer_cells::{
|
||||||
|
LastFinalizedBlockIdCell, LatestBlockMetaCellOwned, LatestBlockMetaCellRef,
|
||||||
|
NSSAStateCellOwned, NSSAStateCellRef,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod sequencer_cells;
|
||||||
|
|
||||||
|
/// 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 metainformation about the latest block meta.
|
||||||
|
pub const DB_META_LATEST_BLOCK_META_KEY: &str = "latest_block_meta";
|
||||||
|
|
||||||
|
/// Key base for storing the NSSA state.
|
||||||
|
pub const DB_NSSA_STATE_KEY: &str = "nssa_state";
|
||||||
|
|
||||||
|
/// Name of state column family.
|
||||||
|
pub const CF_NSSA_STATE_NAME: &str = "cf_nssa_state";
|
||||||
|
|
||||||
|
pub struct RocksDBIO {
|
||||||
|
pub db: DBWithThreadMode<MultiThreaded>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DBIO for RocksDBIO {
|
||||||
|
fn db(&self) -> &DBWithThreadMode<MultiThreaded> {
|
||||||
|
&self.db
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RocksDBIO {
|
||||||
|
pub fn open_or_create(
|
||||||
|
path: &Path,
|
||||||
|
genesis_block: &Block,
|
||||||
|
genesis_msg_id: MantleMsgId,
|
||||||
|
) -> DbResult<Self> {
|
||||||
|
let mut cf_opts = Options::default();
|
||||||
|
cf_opts.set_max_write_buffer_number(16);
|
||||||
|
// ToDo: Add more column families for different data
|
||||||
|
let cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone());
|
||||||
|
let cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone());
|
||||||
|
let cfstate = ColumnFamilyDescriptor::new(CF_NSSA_STATE_NAME, cf_opts.clone());
|
||||||
|
|
||||||
|
let mut db_opts = Options::default();
|
||||||
|
db_opts.create_missing_column_families(true);
|
||||||
|
db_opts.create_if_missing(true);
|
||||||
|
let db = DBWithThreadMode::<MultiThreaded>::open_cf_descriptors(
|
||||||
|
&db_opts,
|
||||||
|
path,
|
||||||
|
vec![cfb, cfmeta, cfstate],
|
||||||
|
)
|
||||||
|
.map_err(|err| DbError::RocksDbError {
|
||||||
|
error: err,
|
||||||
|
additional_info: Some("Failed to open or create DB".to_owned()),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let dbio = Self { db };
|
||||||
|
|
||||||
|
let is_start_set = dbio.get_meta_is_first_block_set()?;
|
||||||
|
if !is_start_set {
|
||||||
|
let block_id = genesis_block.header.block_id;
|
||||||
|
dbio.put_meta_first_block_in_db(genesis_block, genesis_msg_id)?;
|
||||||
|
dbio.put_meta_is_first_block_set()?;
|
||||||
|
dbio.put_meta_last_block_in_db(block_id)?;
|
||||||
|
dbio.put_meta_last_finalized_block_id(None)?;
|
||||||
|
dbio.put_meta_latest_block_meta(&BlockMeta {
|
||||||
|
id: genesis_block.header.block_id,
|
||||||
|
hash: genesis_block.header.hash,
|
||||||
|
msg_id: genesis_msg_id,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(dbio)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(path: &Path) -> DbResult<()> {
|
||||||
|
let mut cf_opts = Options::default();
|
||||||
|
cf_opts.set_max_write_buffer_number(16);
|
||||||
|
// ToDo: Add more column families for different data
|
||||||
|
let _cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone());
|
||||||
|
let _cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone());
|
||||||
|
let _cfstate = ColumnFamilyDescriptor::new(CF_NSSA_STATE_NAME, cf_opts.clone());
|
||||||
|
|
||||||
|
let mut db_opts = Options::default();
|
||||||
|
db_opts.create_missing_column_families(true);
|
||||||
|
db_opts.create_if_missing(true);
|
||||||
|
DBWithThreadMode::<MultiThreaded>::destroy(&db_opts, path)
|
||||||
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columns
|
||||||
|
|
||||||
|
pub fn meta_column(&self) -> Arc<BoundColumnFamily<'_>> {
|
||||||
|
self.db
|
||||||
|
.cf_handle(CF_META_NAME)
|
||||||
|
.expect("Meta column should exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_column(&self) -> Arc<BoundColumnFamily<'_>> {
|
||||||
|
self.db
|
||||||
|
.cf_handle(CF_BLOCK_NAME)
|
||||||
|
.expect("Block column should exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nssa_state_column(&self) -> Arc<BoundColumnFamily<'_>> {
|
||||||
|
self.db
|
||||||
|
.cf_handle(CF_NSSA_STATE_NAME)
|
||||||
|
.expect("State should exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meta
|
||||||
|
|
||||||
|
pub fn get_meta_first_block_in_db(&self) -> DbResult<u64> {
|
||||||
|
self.get::<FirstBlockCell>(()).map(|cell| cell.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_meta_last_block_in_db(&self) -> DbResult<u64> {
|
||||||
|
self.get::<LastBlockCell>(()).map(|cell| cell.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_meta_is_first_block_set(&self) -> DbResult<bool> {
|
||||||
|
Ok(self.get_opt::<FirstBlockSetCell>(())?.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_nssa_state_in_db(&self, state: &V03State, batch: &mut WriteBatch) -> DbResult<()> {
|
||||||
|
self.put_batch(&NSSAStateCellRef(state), (), batch)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_meta_first_block_in_db(&self, block: &Block, msg_id: MantleMsgId) -> DbResult<()> {
|
||||||
|
let cf_meta = self.meta_column();
|
||||||
|
self.db
|
||||||
|
.put_cf(
|
||||||
|
&cf_meta,
|
||||||
|
borsh::to_vec(&DB_META_FIRST_BLOCK_IN_DB_KEY).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_META_FIRST_BLOCK_IN_DB_KEY".to_owned()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
borsh::to_vec(&block.header.block_id).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize first block id".to_owned()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
|
let mut batch = WriteBatch::default();
|
||||||
|
self.put_block(block, msg_id, true, &mut batch)?;
|
||||||
|
self.db.write(batch).map_err(|rerr| {
|
||||||
|
DbError::rocksdb_cast_message(
|
||||||
|
rerr,
|
||||||
|
Some("Failed to write first block in db".to_owned()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_meta_last_block_in_db(&self, block_id: u64) -> DbResult<()> {
|
||||||
|
self.put(&LastBlockCell(block_id), ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_meta_last_block_in_db_batch(
|
||||||
|
&self,
|
||||||
|
block_id: u64,
|
||||||
|
batch: &mut WriteBatch,
|
||||||
|
) -> DbResult<()> {
|
||||||
|
self.put_batch(&LastBlockCell(block_id), (), batch)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_meta_last_finalized_block_id(&self, block_id: Option<u64>) -> DbResult<()> {
|
||||||
|
self.put(&LastFinalizedBlockIdCell(block_id), ())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_meta_is_first_block_set(&self) -> DbResult<()> {
|
||||||
|
self.put(&FirstBlockSetCell(true), ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_meta_latest_block_meta(&self, block_meta: &BlockMeta) -> DbResult<()> {
|
||||||
|
self.put(&LatestBlockMetaCellRef(block_meta), ())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_meta_latest_block_meta_batch(
|
||||||
|
&self,
|
||||||
|
block_meta: &BlockMeta,
|
||||||
|
batch: &mut WriteBatch,
|
||||||
|
) -> DbResult<()> {
|
||||||
|
self.put_batch(&LatestBlockMetaCellRef(block_meta), (), batch)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn latest_block_meta(&self) -> DbResult<BlockMeta> {
|
||||||
|
self.get::<LatestBlockMetaCellOwned>(()).map(|val| val.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_block(
|
||||||
|
&self,
|
||||||
|
block: &Block,
|
||||||
|
msg_id: MantleMsgId,
|
||||||
|
first: bool,
|
||||||
|
batch: &mut WriteBatch,
|
||||||
|
) -> DbResult<()> {
|
||||||
|
let cf_block = self.block_column();
|
||||||
|
|
||||||
|
if !first {
|
||||||
|
let last_curr_block = self.get_meta_last_block_in_db()?;
|
||||||
|
|
||||||
|
if block.header.block_id > last_curr_block {
|
||||||
|
self.put_meta_last_block_in_db_batch(block.header.block_id, batch)?;
|
||||||
|
self.put_meta_latest_block_meta_batch(
|
||||||
|
&BlockMeta {
|
||||||
|
id: block.header.block_id,
|
||||||
|
hash: block.header.hash,
|
||||||
|
msg_id,
|
||||||
|
},
|
||||||
|
batch,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
batch.put_cf(
|
||||||
|
&cf_block,
|
||||||
|
borsh::to_vec(&block.header.block_id).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize block id".to_owned()))
|
||||||
|
})?,
|
||||||
|
borsh::to_vec(block).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize block data".to_owned()))
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_block(&self, block_id: u64) -> DbResult<Option<Block>> {
|
||||||
|
self.get_opt::<BlockCell>(block_id)
|
||||||
|
.map(|opt| opt.map(|val| val.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_nssa_state(&self) -> DbResult<V03State> {
|
||||||
|
self.get::<NSSAStateCellOwned>(()).map(|val| val.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_block(&self, block_id: u64) -> DbResult<()> {
|
||||||
|
let cf_block = self.block_column();
|
||||||
|
let key = borsh::to_vec(&block_id).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize block id".to_owned()))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if self
|
||||||
|
.db
|
||||||
|
.get_cf(&cf_block, &key)
|
||||||
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
return Err(DbError::db_interaction_error(format!(
|
||||||
|
"Block with id {block_id} not found"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.db
|
||||||
|
.delete_cf(&cf_block, key)
|
||||||
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark_block_as_finalized(&self, block_id: u64) -> DbResult<()> {
|
||||||
|
let mut block = self.get_block(block_id)?.ok_or_else(|| {
|
||||||
|
DbError::db_interaction_error(format!("Block with id {block_id} not found"))
|
||||||
|
})?;
|
||||||
|
block.bedrock_status = BedrockStatus::Finalized;
|
||||||
|
|
||||||
|
let cf_block = self.block_column();
|
||||||
|
self.db
|
||||||
|
.put_cf(
|
||||||
|
&cf_block,
|
||||||
|
borsh::to_vec(&block_id).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize block id".to_owned()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
borsh::to_vec(&block).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize block data".to_owned()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
.map_err(|rerr| {
|
||||||
|
DbError::rocksdb_cast_message(
|
||||||
|
rerr,
|
||||||
|
Some(format!("Failed to mark block {block_id} as finalized")),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_all_blocks(&self) -> impl Iterator<Item = DbResult<Block>> {
|
||||||
|
let cf_block = self.block_column();
|
||||||
|
self.db
|
||||||
|
.iterator_cf(&cf_block, rocksdb::IteratorMode::Start)
|
||||||
|
.map(|res| {
|
||||||
|
let (_key, value) = res.map_err(|rerr| {
|
||||||
|
DbError::rocksdb_cast_message(
|
||||||
|
rerr,
|
||||||
|
Some("Failed to get key value pair".to_owned()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
borsh::from_slice::<Block>(&value).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to deserialize block data".to_owned()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn atomic_update(
|
||||||
|
&self,
|
||||||
|
block: &Block,
|
||||||
|
msg_id: MantleMsgId,
|
||||||
|
state: &V03State,
|
||||||
|
) -> DbResult<()> {
|
||||||
|
let block_id = block.header.block_id;
|
||||||
|
let mut batch = WriteBatch::default();
|
||||||
|
self.put_block(block, msg_id, false, &mut batch)?;
|
||||||
|
self.put_nssa_state_in_db(state, &mut batch)?;
|
||||||
|
self.db.write(batch).map_err(|rerr| {
|
||||||
|
DbError::rocksdb_cast_message(
|
||||||
|
rerr,
|
||||||
|
Some(format!("Failed to udpate db with block {block_id}")),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
132
storage/src/sequencer/sequencer_cells.rs
Normal file
132
storage/src/sequencer/sequencer_cells.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use borsh::{BorshDeserialize, BorshSerialize};
|
||||||
|
use common::block::BlockMeta;
|
||||||
|
use nssa::V03State;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
CF_META_NAME, DbResult,
|
||||||
|
cells::{SimpleReadableCell, SimpleStorableCell, SimpleWritableCell},
|
||||||
|
error::DbError,
|
||||||
|
sequencer::{
|
||||||
|
CF_NSSA_STATE_NAME, DB_META_LAST_FINALIZED_BLOCK_ID, DB_META_LATEST_BLOCK_META_KEY,
|
||||||
|
DB_NSSA_STATE_KEY,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(BorshDeserialize)]
|
||||||
|
pub struct NSSAStateCellOwned(pub V03State);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for NSSAStateCellOwned {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_NSSA_STATE_KEY;
|
||||||
|
const CF_NAME: &'static str = CF_NSSA_STATE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for NSSAStateCellOwned {}
|
||||||
|
|
||||||
|
#[derive(BorshSerialize)]
|
||||||
|
pub struct NSSAStateCellRef<'state>(pub &'state V03State);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for NSSAStateCellRef<'_> {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_NSSA_STATE_KEY;
|
||||||
|
const CF_NAME: &'static str = CF_NSSA_STATE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for NSSAStateCellRef<'_> {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize last state".to_owned()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct LastFinalizedBlockIdCell(pub Option<u64>);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for LastFinalizedBlockIdCell {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_META_LAST_FINALIZED_BLOCK_ID;
|
||||||
|
const CF_NAME: &'static str = CF_META_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for LastFinalizedBlockIdCell {}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for LastFinalizedBlockIdCell {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize last finalized block id".to_owned()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BorshDeserialize)]
|
||||||
|
pub struct LatestBlockMetaCellOwned(pub BlockMeta);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for LatestBlockMetaCellOwned {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_META_LATEST_BLOCK_META_KEY;
|
||||||
|
const CF_NAME: &'static str = CF_META_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleReadableCell for LatestBlockMetaCellOwned {}
|
||||||
|
|
||||||
|
#[derive(BorshSerialize)]
|
||||||
|
pub struct LatestBlockMetaCellRef<'blockmeta>(pub &'blockmeta BlockMeta);
|
||||||
|
|
||||||
|
impl SimpleStorableCell for LatestBlockMetaCellRef<'_> {
|
||||||
|
type KeyParams = ();
|
||||||
|
|
||||||
|
const CELL_NAME: &'static str = DB_META_LATEST_BLOCK_META_KEY;
|
||||||
|
const CF_NAME: &'static str = CF_META_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleWritableCell for LatestBlockMetaCellRef<'_> {
|
||||||
|
fn value_constructor(&self) -> DbResult<Vec<u8>> {
|
||||||
|
borsh::to_vec(&self).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(err, Some("Failed to serialize last block meta".to_owned()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod uniform_tests {
|
||||||
|
use crate::{
|
||||||
|
cells::SimpleStorableCell as _,
|
||||||
|
sequencer::sequencer_cells::{
|
||||||
|
LatestBlockMetaCellOwned, LatestBlockMetaCellRef, NSSAStateCellOwned, NSSAStateCellRef,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn state_ref_and_owned_is_aligned() {
|
||||||
|
assert_eq!(NSSAStateCellRef::CELL_NAME, NSSAStateCellOwned::CELL_NAME);
|
||||||
|
assert_eq!(NSSAStateCellRef::CF_NAME, NSSAStateCellOwned::CF_NAME);
|
||||||
|
assert_eq!(
|
||||||
|
NSSAStateCellRef::key_constructor(()).unwrap(),
|
||||||
|
NSSAStateCellOwned::key_constructor(()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_meta_ref_and_owned_is_aligned() {
|
||||||
|
assert_eq!(
|
||||||
|
LatestBlockMetaCellRef::CELL_NAME,
|
||||||
|
LatestBlockMetaCellOwned::CELL_NAME
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
LatestBlockMetaCellRef::CF_NAME,
|
||||||
|
LatestBlockMetaCellOwned::CF_NAME
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
LatestBlockMetaCellRef::key_constructor(()).unwrap(),
|
||||||
|
LatestBlockMetaCellOwned::key_constructor(()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user