Skip to content

Commit e09d73d

Browse files
committed
blockstore: add DoubleMerkleMeta column
1 parent d6f08a5 commit e09d73d

File tree

6 files changed

+106
-2
lines changed

6 files changed

+106
-2
lines changed

ledger/src/blockstore.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ pub struct Blockstore {
275275
alt_data_shred_cf: LedgerColumn<cf::AlternateShredData>,
276276
alt_merkle_root_meta_cf: LedgerColumn<cf::AlternateMerkleRootMeta>,
277277
parent_meta_cf: LedgerColumn<cf::ParentMeta>,
278+
double_merkle_meta_cf: LedgerColumn<cf::DoubleMerkleMeta>,
278279

279280
highest_primary_index_slot: RwLock<Option<Slot>>,
280281
max_root: AtomicU64,
@@ -458,6 +459,7 @@ impl Blockstore {
458459
let alt_data_shred_cf = db.column();
459460
let alt_merkle_root_meta_cf = db.column();
460461
let parent_meta_cf = db.column();
462+
let double_merkle_meta_cf = db.column();
461463

462464
// Get max root or 0 if it doesn't exist
463465
let max_root = roots_cf
@@ -499,6 +501,7 @@ impl Blockstore {
499501
alt_data_shred_cf,
500502
alt_merkle_root_meta_cf,
501503
parent_meta_cf,
504+
double_merkle_meta_cf,
502505

503506
highest_primary_index_slot: RwLock::<Option<Slot>>::default(),
504507
new_shreds_signals: Mutex::default(),

ledger/src/blockstore/blockstore_purge.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,10 @@ impl Blockstore {
332332
& self
333333
.parent_meta_cf
334334
.delete_range_in_batch(write_batch, from_slot, to_slot)
335+
.is_ok()
336+
& self
337+
.double_merkle_meta_cf
338+
.delete_range_in_batch(write_batch, from_slot, to_slot)
335339
.is_ok();
336340

337341
match purge_type {
@@ -437,6 +441,14 @@ impl Blockstore {
437441
.alt_merkle_root_meta_cf
438442
.delete_file_in_range(from_slot, to_slot)
439443
.is_ok()
444+
& self
445+
.parent_meta_cf
446+
.delete_file_in_range(from_slot, to_slot)
447+
.is_ok()
448+
& self
449+
.double_merkle_meta_cf
450+
.delete_file_in_range(from_slot, to_slot)
451+
.is_ok()
440452
}
441453

442454
/// Returns true if the special columns, TransactionStatus and

ledger/src/blockstore/column.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,16 @@ pub mod columns {
288288
/// * index type: `(Slot, BlockLocation)`
289289
/// * value type: [`blockstore_meta::ParentMeta`]
290290
pub struct ParentMeta;
291+
292+
#[derive(Debug)]
293+
/// The double merkle root metadata column
294+
///
295+
/// This column stores details about the double merkle root of a block.
296+
/// We update this column when we finish ingesting all the shreds of the block.
297+
///
298+
/// * index type: `(Slot, BlockLocation)`
299+
/// * value type: [`blockstore_meta::DoubleMerkleMeta`]
300+
pub struct DoubleMerkleMeta;
291301
}
292302

293303
macro_rules! convert_column_index_to_key_bytes {
@@ -1118,3 +1128,52 @@ impl ColumnName for columns::ParentMeta {
11181128
impl TypedColumn for columns::ParentMeta {
11191129
type Type = blockstore_meta::ParentMeta;
11201130
}
1131+
1132+
impl Column for columns::DoubleMerkleMeta {
1133+
type Index = (Slot, BlockLocation);
1134+
// Key size: Slot (8 bytes) + Hash (32 bytes)
1135+
// When BlockLocation::Original, the hash is Hash::default().
1136+
type Key = [u8; std::mem::size_of::<Slot>() + HASH_BYTES];
1137+
1138+
#[inline]
1139+
fn key((slot, location): &Self::Index) -> Self::Key {
1140+
let mut key = [0u8; std::mem::size_of::<Slot>() + HASH_BYTES];
1141+
key[..8].copy_from_slice(&slot.to_le_bytes());
1142+
1143+
let hash_bytes = match location {
1144+
BlockLocation::Original => &Hash::default().to_bytes(),
1145+
BlockLocation::Alternate { block_id } => &block_id.to_bytes(),
1146+
};
1147+
1148+
key[8..40].copy_from_slice(hash_bytes);
1149+
1150+
key
1151+
}
1152+
1153+
fn index(key: &[u8]) -> Self::Index {
1154+
let slot = Slot::from_le_bytes(key[0..8].try_into().unwrap());
1155+
let hash = Hash::new_from_array(key[8..40].try_into().unwrap());
1156+
let location = match hash == Hash::default() {
1157+
true => BlockLocation::Original,
1158+
false => BlockLocation::Alternate { block_id: hash },
1159+
};
1160+
1161+
(slot, location)
1162+
}
1163+
1164+
fn as_index(slot: Slot) -> Self::Index {
1165+
(slot, BlockLocation::Original)
1166+
}
1167+
1168+
fn slot((slot, _location): Self::Index) -> Slot {
1169+
slot
1170+
}
1171+
}
1172+
1173+
impl ColumnName for columns::DoubleMerkleMeta {
1174+
const NAME: &'static str = "double_merkle_meta";
1175+
}
1176+
1177+
impl TypedColumn for columns::DoubleMerkleMeta {
1178+
type Type = blockstore_meta::DoubleMerkleMeta;
1179+
}

ledger/src/blockstore_db.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ impl Rocks {
201201
new_cf_descriptor::<columns::AlternateShredData>(options, oldest_slot),
202202
new_cf_descriptor::<columns::AlternateMerkleRootMeta>(options, oldest_slot),
203203
new_cf_descriptor::<columns::ParentMeta>(options, oldest_slot),
204+
new_cf_descriptor::<columns::DoubleMerkleMeta>(options, oldest_slot),
204205
];
205206

206207
// If the access type is Secondary, we don't need to open all of the
@@ -249,7 +250,7 @@ impl Rocks {
249250
cf_descriptors
250251
}
251252

252-
const fn columns() -> [&'static str; 27] {
253+
const fn columns() -> [&'static str; 28] {
253254
[
254255
columns::ErasureMeta::NAME,
255256
columns::DeadSlots::NAME,
@@ -278,6 +279,7 @@ impl Rocks {
278279
columns::AlternateShredData::NAME,
279280
columns::AlternateMerkleRootMeta::NAME,
280281
columns::ParentMeta::NAME,
282+
columns::DoubleMerkleMeta::NAME,
281283
]
282284
}
283285

ledger/src/blockstore_meta.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use {
1111
solana_hash::Hash,
1212
std::{
1313
collections::BTreeSet,
14+
fmt::Display,
1415
ops::{Range, RangeBounds},
1516
},
1617
};
@@ -464,6 +465,15 @@ impl BlockVersions {
464465
}
465466
}
466467

468+
impl Display for BlockLocation {
469+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
470+
match self {
471+
BlockLocation::Original => write!(f, "Original"),
472+
BlockLocation::Alternate { block_id } => write!(f, "Alternate({block_id})"),
473+
}
474+
}
475+
}
476+
467477
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
468478
pub enum FrozenHashVersioned {
469479
Current(FrozenHashStatus),
@@ -1000,6 +1010,24 @@ impl ParentMeta {
10001010
}
10011011
}
10021012

1013+
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
1014+
pub struct DoubleMerkleMeta {
1015+
/// The double merkle root computed as the root of the merkle tree
1016+
/// containing the merkle roots of each fec set + the parent info (parent_slot, parent_double_merkle_root)
1017+
pub double_merkle_root: Hash,
1018+
1019+
/// The number of fec sets in this block
1020+
pub fec_set_count: usize,
1021+
1022+
/// The merkle proofs
1023+
/// index of [0, fec_set_count) corresponds to the proofs for each fec set leaf node
1024+
/// index of fec_set_count corresponds to the proof for the parent info node
1025+
///
1026+
/// The size of this vec is `fec_set_count + 1`
1027+
/// Each inner Vec<u8> contains concatenated proof entries for that leaf
1028+
pub proofs: Vec<Vec<u8>>,
1029+
}
1030+
10031031
#[cfg(test)]
10041032
mod test {
10051033
use {

ledger/src/shred.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ use {solana_keypair::Keypair, solana_perf::packet::Packet, solana_signer::Signer
8585

8686
mod common;
8787
pub(crate) mod merkle;
88-
mod merkle_tree;
88+
pub(crate) mod merkle_tree;
8989
mod payload;
9090
mod shred_code;
9191
mod shred_data;

0 commit comments

Comments
 (0)