-
Notifications
You must be signed in to change notification settings - Fork 34
blockstore: compute and populate DoubleMerkleRootMeta #613
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
759a827
2b29eba
4013fce
51cd892
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,7 +18,11 @@ use { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| leader_schedule_cache::LeaderScheduleCache, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| next_slots_iterator::NextSlotsIterator, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shred::{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self, ErasureSetId, ProcessShredsStats, ReedSolomonCache, Shred, ShredData, ShredFlags, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| merkle_tree::{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| get_proof_size, make_merkle_proof, make_merkle_tree, SIZE_OF_MERKLE_PROOF_ENTRY, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ErasureSetId, ProcessShredsStats, ReedSolomonCache, Shred, ShredData, ShredFlags, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ShredId, ShredType, Shredder, DATA_SHREDS_PER_FEC_BLOCK, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| slot_stats::{ShredSource, SlotsStats}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -49,6 +53,7 @@ use { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solana_metrics::datapoint_error, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solana_pubkey::Pubkey, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solana_runtime::bank::Bank, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solana_sha256_hasher::hashv, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solana_signature::Signature, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solana_signer::Signer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solana_storage_proto::{StoredExtendedRewards, StoredTransactionStatusMeta}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -275,6 +280,7 @@ pub struct Blockstore { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alt_data_shred_cf: LedgerColumn<cf::AlternateShredData>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alt_merkle_root_meta_cf: LedgerColumn<cf::AlternateMerkleRootMeta>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parent_meta_cf: LedgerColumn<cf::ParentMeta>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| double_merkle_meta_cf: LedgerColumn<cf::DoubleMerkleMeta>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| highest_primary_index_slot: RwLock<Option<Slot>>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_root: AtomicU64, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -458,6 +464,7 @@ impl Blockstore { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let alt_data_shred_cf = db.column(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let alt_merkle_root_meta_cf = db.column(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let parent_meta_cf = db.column(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let double_merkle_meta_cf = db.column(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get max root or 0 if it doesn't exist | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let max_root = roots_cf | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -499,6 +506,7 @@ impl Blockstore { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alt_data_shred_cf, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alt_merkle_root_meta_cf, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parent_meta_cf, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| double_merkle_meta_cf, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| highest_primary_index_slot: RwLock::<Option<Slot>>::default(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_shreds_signals: Mutex::default(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -866,6 +874,119 @@ impl Blockstore { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Gets the double merkle root for the given block, computing it if necessary. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Fails and returns `None` if the block is missing or not full | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub fn get_double_merkle_root( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| &self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| slot: Slot, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| block_location: BlockLocation, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> Option<Hash> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let Some(double_merkle_meta) = self | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .double_merkle_meta_cf | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .get((slot, block_location)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("Blockstore operations must succeed") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Some(double_merkle_meta.double_merkle_root); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.compute_double_merkle_root(slot, block_location) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Computes the double merkle root & proofs for the given block and inserts the DoubleMerkleMeta. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Fails if the slot is not full returning `None` otherwise returns the double merkle root | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn compute_double_merkle_root( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| &self, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| slot: Slot, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| block_location: BlockLocation, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> Option<Hash> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let slot_meta = self | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .meta_cf | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .get(slot) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("Blockstore operations must succeed")?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !slot_meta.is_full() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return None; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let last_index = slot_meta.last_index.expect("Slot is full"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This function is only used post Alpenglow, so implicitely gated by SIMD-0317 as that is a prereq | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let fec_set_count = (last_index / (DATA_SHREDS_PER_FEC_BLOCK as u64) + 1) as usize; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let parent_meta = self | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .parent_meta_cf | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .get((slot, block_location)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("Blockstore operations must succeed") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("Slot cannot be full without parent"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Collect merkle roots for each FEC set | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let fec_set_indices = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (0..fec_set_count).map(|i| (slot, (i * DATA_SHREDS_PER_FEC_BLOCK) as u32)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would use Slightly far-fetched - given proposals to remove CU limits and have block limits only be time-based, if a malicious leader constructed a block with a very large number of no-ops, I wonder whether we could have
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we're actually protected by that type of attack here Lines 801 to 803 in 079cd89
Before the shred is even inserted into blockstore we verify that the index is less than 32k, so |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let keys = self.merkle_root_meta_cf.multi_get_keys(fec_set_indices); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut merkle_tree_leaves = self | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .merkle_root_meta_cf | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .multi_get_bytes(&keys) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(|get_result| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let bytes = get_result | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("Blockstore operations must succeed") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("Merkle root meta must exist for all fec sets in full slot"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let merkle_root = bincode::deserialize::<MerkleRootMeta>(bytes.as_ref()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("Merkle root meta column only contains valid MerkleRootMetas") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .merkle_root() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expect("Legacy shreds no longer exist, merkle root must be present"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(merkle_root) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .collect::<Vec<_>>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Add parent info as the last leaf | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let parent_info_hash = hashv(&[ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| &parent_meta.parent_slot.to_le_bytes(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parent_meta.parent_block_id.as_ref(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| merkle_tree_leaves.push(Ok(parent_info_hash)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut merkle_tree_leaves = self | |
| .merkle_root_meta_cf | |
| .multi_get_bytes(&keys) | |
| .map(|get_result| { | |
| let bytes = get_result | |
| .expect("Blockstore operations must succeed") | |
| .expect("Merkle root meta must exist for all fec sets in full slot"); | |
| let merkle_root = bincode::deserialize::<MerkleRootMeta>(bytes.as_ref()) | |
| .expect("Merkle root meta column only contains valid MerkleRootMetas") | |
| .merkle_root() | |
| .expect("Legacy shreds no longer exist, merkle root must be present"); | |
| Ok(merkle_root) | |
| }) | |
| .collect::<Vec<_>>(); | |
| // Add parent info as the last leaf | |
| let parent_info_hash = hashv(&[ | |
| &parent_meta.parent_slot.to_le_bytes(), | |
| parent_meta.parent_block_id.as_ref(), | |
| ]); | |
| merkle_tree_leaves.push(Ok(parent_info_hash)); | |
| let merkle_tree_leaves: Vec<_> = self | |
| .merkle_root_meta_cf | |
| .multi_get_bytes(&keys) | |
| .map(|get_result| { | |
| let bytes = get_result | |
| .expect("Blockstore operations must succeed") | |
| .expect("Merkle root meta must exist for all fec sets in full slot"); | |
| bincode::deserialize::<MerkleRootMeta>(bytes.as_ref()) | |
| .expect("Merkle root meta column only contains valid MerkleRootMetas") | |
| .merkle_root() | |
| .expect("Legacy shreds no longer exist, merkle root must be present") | |
| }) | |
| // Add parent info as the last leaf | |
| .chain(std::iter::once(hashv(&[ | |
| &parent_meta.parent_slot.to_le_bytes(), | |
| parent_meta.parent_block_id.as_ref(), | |
| ]))) | |
| .collect(); |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| let tree_size = fec_set_count + 1; | |
| let mut proofs = Vec::with_capacity(tree_size); | |
| for leaf_index in 0..tree_size { | |
| let proof_iter = make_merkle_proof(leaf_index, tree_size, &merkle_tree); | |
| let proof: Vec<u8> = proof_iter | |
| .flat_map(|proof| { | |
| proof | |
| .expect("Merkle proof construction cannot have failed") | |
| .as_slice() | |
| }) | |
| .copied() | |
| .collect(); | |
| debug_assert_eq!( | |
| proof.len(), | |
| get_proof_size(tree_size) as usize * SIZE_OF_MERKLE_PROOF_ENTRY | |
| ); | |
| proofs.push(proof); | |
| } | |
| let tree_size = fec_set_count + 1; | |
| let proofs: Vec<Vec<u8>> = (0..tree_size) | |
| .map(|leaf_index| { | |
| make_merkle_proof(leaf_index, tree_size, &merkle_tree) | |
| .map(|hash| hash.expect("Merkle proof construction cannot fail")) | |
| .flat_map(|hash| hash.as_ref()) | |
| .copied() | |
| .collect() | |
| }) | |
| .inspect(|proof| { | |
| debug_assert_eq!( | |
| proof.len(), | |
| get_proof_size(tree_size) as usize * SIZE_OF_MERKLE_PROOF_ENTRY | |
| ); | |
| }) | |
| .collect(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -332,6 +332,10 @@ impl Blockstore { | |
| & self | ||
| .parent_meta_cf | ||
| .delete_range_in_batch(write_batch, from_slot, to_slot) | ||
| .is_ok() | ||
| & self | ||
| .double_merkle_meta_cf | ||
| .delete_range_in_batch(write_batch, from_slot, to_slot) | ||
| .is_ok(); | ||
|
|
||
| match purge_type { | ||
|
|
@@ -437,6 +441,14 @@ impl Blockstore { | |
| .alt_merkle_root_meta_cf | ||
| .delete_file_in_range(from_slot, to_slot) | ||
| .is_ok() | ||
| & self | ||
| .parent_meta_cf | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oof, good catch |
||
| .delete_file_in_range(from_slot, to_slot) | ||
| .is_ok() | ||
| & self | ||
| .double_merkle_meta_cf | ||
| .delete_file_in_range(from_slot, to_slot) | ||
| .is_ok() | ||
| } | ||
|
|
||
| /// Returns true if the special columns, TransactionStatus and | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: implicitly