Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

blockstore: add merkle root to ErasureMeta column family #33848

Closed

Conversation

AshwinSekar
Copy link
Contributor

@AshwinSekar AshwinSekar commented Oct 24, 2023

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

@AshwinSekar AshwinSekar force-pushed the merkle-erasure-blockstore branch from 5e4cb20 to 924d4fb Compare October 24, 2023 21:06
@@ -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();
Copy link
Contributor Author

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.

@AshwinSekar AshwinSekar marked this pull request as ready for review October 24, 2023 21:37
@AshwinSekar AshwinSekar added the v1.17 PRs that should be backported to v1.17 label Oct 24, 2023
@codecov
Copy link

codecov bot commented Oct 24, 2023

Codecov Report

Merging #33848 (9d9252a) into master (a851670) will increase coverage by 0.0%.
Report is 2 commits behind head on master.
The diff coverage is 92.3%.

@@           Coverage Diff           @@
##           master   #33848   +/-   ##
=======================================
  Coverage    81.8%    81.8%           
=======================================
  Files         809      809           
  Lines      217708   217796   +88     
=======================================
+ Hits       178283   178357   +74     
- Misses      39425    39439   +14     

@@ -3,7 +3,7 @@ use {
itertools::Itertools,
solana_ledger::{
blockstore::BlockstoreError,
blockstore_meta::{DuplicateSlotProof, ErasureMeta},
blockstore_meta::{DuplicateSlotProof, MerkleErasureMeta},
Copy link
Contributor

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.


#[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq)]
/// Erasure coding information for merkle shreds
pub struct MerkleErasureMeta {
Copy link
Contributor

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.

Copy link
Contributor Author

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

Comment on lines 151 to 152
pub(crate) num_data: usize,
pub(crate) num_coding: usize,
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Comment on lines +805 to +810
/// 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>;
}

Copy link
Contributor

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))
         }
 

Copy link
Contributor Author

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.

@AshwinSekar AshwinSekar force-pushed the merkle-erasure-blockstore branch from 924d4fb to c5bf204 Compare October 25, 2023 18:54
@AshwinSekar AshwinSekar force-pushed the merkle-erasure-blockstore branch from c5bf204 to 9d9252a Compare October 25, 2023 19:02
@AshwinSekar
Copy link
Contributor Author

After some offline discussion, it seems possible to detect merkle root conflicts without the requirement of an ErasureMeta, which we originally thought was not possible.

Given this, I am closing this in favor of the original idea of adding a new column. We can add a new MerkleRootMeta column that contains the merkle root and meta information instead of reusing the ErasureMeta. This will avoid the need for any backports as well.

will continue here #33979

@AshwinSekar AshwinSekar closed this Nov 7, 2023
@AshwinSekar AshwinSekar self-assigned this Nov 29, 2023
Copy link
Contributor

mergify bot commented Nov 29, 2023

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.

@AshwinSekar AshwinSekar deleted the merkle-erasure-blockstore branch November 29, 2023 19:10
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
v1.17 PRs that should be backported to v1.17
Projects
Development

Successfully merging this pull request may close these issues.

2 participants