-
Notifications
You must be signed in to change notification settings - Fork 4.5k
blockstore: add merkle root to ErasureMeta column family #33848
blockstore: add merkle root to ErasureMeta column family #33848
Conversation
5e4cb20
to
924d4fb
Compare
@@ -331,11 +345,12 @@ impl ErasureMeta { | |||
num_coding: usize::from(shred.num_coding_shreds().ok()?), | |||
}; | |||
let first_coding_index = u64::from(shred.first_coding_index()?); | |||
let erasure_meta = ErasureMeta { | |||
let merkle_root = Hash::default(); |
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.
next change in master will populate this from the coding shred, but I don't think that needs to be part of this backport change.
Codecov Report
@@ Coverage Diff @@
## master #33848 +/- ##
=======================================
Coverage 81.8% 81.8%
=======================================
Files 809 809
Lines 217708 217796 +88
=======================================
+ Hits 178283 178357 +74
- Misses 39425 39439 +14 |
gossip/src/duplicate_shred.rs
Outdated
@@ -3,7 +3,7 @@ use { | |||
itertools::Itertools, | |||
solana_ledger::{ | |||
blockstore::BlockstoreError, | |||
blockstore_meta::{DuplicateSlotProof, ErasureMeta}, | |||
blockstore_meta::{DuplicateSlotProof, MerkleErasureMeta}, |
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.
Can we rename the old struct ErasureMetaLegacy
and use ErasureMeta
for the new one?
That would be more obvious and self-documenting that the new code should not bother with the legacy one, and there is only one type that matters.
ledger/src/blockstore_meta.rs
Outdated
|
||
#[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq)] | ||
/// Erasure coding information for merkle shreds | ||
pub struct MerkleErasureMeta { |
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.
don't we need the coding shred index from which this erasure meta was populated from here?
for example in the case we want to generate a duplicate proof, we need the coding shred which contains this erasure meta.
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.
yeah good point, was planning to scan using the first_coding_index
, but we can just put the coding shred index and save some blockstore reads
ledger/src/blockstore_meta.rs
Outdated
pub(crate) num_data: usize, | ||
pub(crate) num_coding: usize, |
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.
why do we need this pub(crate)
here? is this just for tests?
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.
yeah for tests, i just made a test impl instead.
/// Helper trait to transition a column between bincode formats | ||
pub trait BincodeTypeTransition: Column + TypedColumn { | ||
/// This should have a different serialized size than the TypedColumn::Type | ||
type OldType: Serialize + DeserializeOwned + Into<Self::Type>; | ||
} | ||
|
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.
This type trait and its associated code is pretty verbose and actually adding more complexity here.
Might be simple just to do something like below:
diff --git a/ledger/src/blockstore_db.rs b/ledger/src/blockstore_db.rs
index b65df82ee0..eebf163400 100644
--- a/ledger/src/blockstore_db.rs
+++ b/ledger/src/blockstore_db.rs
@@ -1586,7 +1586,7 @@ where
}
}
-impl<C> LedgerColumn<C>
+impl<C: 'static> LedgerColumn<C>
where
C: TypedColumn + ColumnName,
{
@@ -1635,7 +1635,12 @@ where
&self.read_perf_status,
);
if let Some(pinnable_slice) = self.backend.get_pinned_cf(self.handle(), key)? {
- let value = deserialize(pinnable_slice.as_ref())?;
+ use std::any::TypeId;
+ let value = deserialize(pinnable_slice.as_ref()).or_else(|err| {
+ if TypeId::of::<C>() == TypeId::of::<columns::MerkleErasureMeta>() {
+ // retry with the old erasure meta type.
+ // ...
+ }
+ Err(err)
+ })?;
result = Ok(Some(value))
}
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.
I added it to provide an easy way to transition types of already existing columns in blockstore. Similar to ColumnIndexDeprecation.
All you have to do is implement the trait and TypedColumn. And after the old type is no longer in blockstore, you can just remove the trait impl and the associated migration test.
Figured its worth adding the complexity here to make future transitions frictionless.
924d4fb
to
c5bf204
Compare
c5bf204
to
9d9252a
Compare
After some offline discussion, it seems possible to detect merkle root conflicts without the requirement of an Given this, I am closing this in favor of the original idea of adding a new column. We can add a new will continue here #33979 |
Backports to the beta branch are to be avoided unless absolutely necessary for fixing bugs, security issues, and perf regressions. Changes intended for backport should be structured such that a minimum effective diff can be committed separately from any refactoring, plumbing, cleanup, etc that are not strictly necessary to achieve the goal. Any of the latter should go only into master and ride the normal stabilization schedule. Exceptions include CI/metrics changes, CLI improvements and documentation updates on a case by case basis. |
Problem
In order to detect duplicate blocks with conflicting merkle roots we need to be able to access the merkle root for each FEC set.
We store the merkle root along with the existing
ErasureMeta
for each FEC set.Summary of Changes
This change allows us to read blockstore in both formats, with or without the merkle root. It is intended to be backported.
Contributes to #33644