diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index ce9336e1132192..5c0de281f58987 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -214,6 +214,7 @@ pub struct Blockstore { program_costs_cf: LedgerColumn, bank_hash_cf: LedgerColumn, optimistic_slots_cf: LedgerColumn, + merkle_root_cf: LedgerColumn, last_root: RwLock, insert_shreds_lock: Mutex<()>, new_shreds_signals: Mutex>>, @@ -315,6 +316,7 @@ impl Blockstore { let program_costs_cf = db.column(); let bank_hash_cf = db.column(); let optimistic_slots_cf = db.column(); + let merkle_root_cf = db.column(); let db = Arc::new(db); @@ -352,6 +354,7 @@ impl Blockstore { program_costs_cf, bank_hash_cf, optimistic_slots_cf, + merkle_root_cf, new_shreds_signals: Mutex::default(), completed_slots_senders: Mutex::default(), shred_timing_point_sender: None, @@ -721,6 +724,7 @@ impl Blockstore { self.program_costs_cf.submit_rocksdb_cf_metrics(); self.bank_hash_cf.submit_rocksdb_cf_metrics(); self.optimistic_slots_cf.submit_rocksdb_cf_metrics(); + self.merkle_root_cf.submit_rocksdb_cf_metrics(); } fn try_shred_recovery( @@ -3135,6 +3139,14 @@ impl Blockstore { .unwrap_or(false) } + pub fn insert_merkle_root(&self, slot: Slot, fec_index: u64, hash: &Hash) -> Result<()> { + self.merkle_root_cf.put((slot, fec_index), hash) + } + + pub fn get_merkle_root(&self, slot: Slot, fec_index: u64) -> Result> { + self.merkle_root_cf.get((slot, fec_index)) + } + pub fn insert_optimistic_slot( &self, slot: Slot, diff --git a/ledger/src/blockstore/blockstore_purge.rs b/ledger/src/blockstore/blockstore_purge.rs index 9669f8bd305a00..38580b0f2ecf1b 100644 --- a/ledger/src/blockstore/blockstore_purge.rs +++ b/ledger/src/blockstore/blockstore_purge.rs @@ -220,6 +220,10 @@ impl Blockstore { & self .db .delete_range_cf::(&mut write_batch, from_slot, to_slot) + .is_ok() + & self + .db + .delete_range_cf::(&mut write_batch, from_slot, to_slot) .is_ok(); match purge_type { PurgeType::Exact => { @@ -329,6 +333,10 @@ impl Blockstore { .db .delete_file_in_range_cf::(from_slot, to_slot) .is_ok() + & self + .db + .delete_file_in_range_cf::(from_slot, to_slot) + .is_ok() } /// Returns true if the special columns, TransactionStatus and diff --git a/ledger/src/blockstore_db.rs b/ledger/src/blockstore_db.rs index b65df82ee00c9e..d113378646e0ab 100644 --- a/ledger/src/blockstore_db.rs +++ b/ledger/src/blockstore_db.rs @@ -29,6 +29,7 @@ use { solana_accounts_db::hardened_unpack::UnpackError, solana_sdk::{ clock::{Slot, UnixTimestamp}, + hash::Hash, pubkey::Pubkey, signature::Signature, }, @@ -103,6 +104,8 @@ const BLOCK_HEIGHT_CF: &str = "block_height"; const PROGRAM_COSTS_CF: &str = "program_costs"; /// Column family for optimistic slots const OPTIMISTIC_SLOTS_CF: &str = "optimistic_slots"; +/// Column family for merkle roots +const MERKLE_ROOT_CF: &str = "merkle_root"; #[derive(Error, Debug)] pub enum BlockstoreError { @@ -339,6 +342,19 @@ pub mod columns { /// * value type: [`blockstore_meta::OptimisticSlotMetaVersioned`] pub struct OptimisticSlots; + #[derive(Debug)] + /// The merkle root column + /// + /// This column stores the merkle root for each FEC set. + /// Each merkle shred is part of a merkle tree for + /// its FEC set. This column stores that merkle root. + /// + /// Its index type is (Slot, FEC) set index. + /// + /// * index type: `crate::shred::ErasureSetId` `(Slot, fec_set_index: u64)` + /// * value type: [`solana_sdk::hash::Hash`]` + pub struct MerkleRoot; + // When adding a new column ... // - Add struct below and implement `Column` and `ColumnName` traits // - Add descriptor in Rocks::cf_descriptors() and name in Rocks::columns() @@ -474,6 +490,7 @@ impl Rocks { new_cf_descriptor::(options, oldest_slot), new_cf_descriptor::(options, oldest_slot), new_cf_descriptor::(options, oldest_slot), + new_cf_descriptor::(options, oldest_slot), ] } @@ -501,6 +518,7 @@ impl Rocks { BlockHeight::NAME, ProgramCosts::NAME, OptimisticSlots::NAME, + MerkleRoot::NAME, ] } @@ -1227,6 +1245,39 @@ impl TypedColumn for columns::OptimisticSlots { type Type = blockstore_meta::OptimisticSlotMetaVersioned; } +impl Column for columns::MerkleRoot { + type Index = (Slot, u64); + + fn index(key: &[u8]) -> (Slot, u64) { + let slot = BigEndian::read_u64(&key[..8]); + let set_index = BigEndian::read_u64(&key[8..]); + + (slot, set_index) + } + + fn key((slot, set_index): (Slot, u64)) -> Vec { + let mut key = vec![0; 16]; + BigEndian::write_u64(&mut key[..8], slot); + BigEndian::write_u64(&mut key[8..], set_index); + key + } + + fn slot(index: Self::Index) -> Slot { + index.0 + } + + fn as_index(slot: Slot) -> Self::Index { + (slot, 0) + } +} + +impl ColumnName for columns::MerkleRoot { + const NAME: &'static str = MERKLE_ROOT_CF; +} +impl TypedColumn for columns::MerkleRoot { + type Type = Hash; +} + #[derive(Debug)] pub struct Database { backend: Arc,