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

add merkle root column in blockstore #33807

Closed

Conversation

AshwinSekar
Copy link
Contributor

@AshwinSekar AshwinSekar commented Oct 21, 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

This is the preliminary change to add a merkle root column for use in further changes to store the merkle root for shreds received.

Summary of Changes

Add merkle root column

Contributes to #33644

@codecov
Copy link

codecov bot commented Oct 21, 2023

Codecov Report

Merging #33807 (70b60ab) into master (5a96352) will increase coverage by 0.0%.
The diff coverage is 53.3%.

@@           Coverage Diff           @@
##           master   #33807   +/-   ##
=======================================
  Coverage    81.8%    81.8%           
=======================================
  Files         807      807           
  Lines      217492   217522   +30     
=======================================
+ Hits       178091   178118   +27     
- Misses      39401    39404    +3     

@AshwinSekar AshwinSekar force-pushed the merkle-erasure-blockstore branch from e3c8126 to 974b1a7 Compare October 21, 2023 07:01
@AshwinSekar AshwinSekar force-pushed the merkle-erasure-blockstore branch from 974b1a7 to 70b60ab Compare October 21, 2023 07:02
@AshwinSekar AshwinSekar marked this pull request as ready for review October 21, 2023 07:03
///
/// * index type: `crate::shred::ErasureSetId` `(Slot, fec_set_index: u64)`
/// * value type: [`solana_sdk::hash::Hash`]`
pub struct MerkleRoot;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@behzadnouri I decided to add a new column instead of modifying the existing ErasureMeta because ErasureMeta is only populated once we insert a coding shred.

This approach will allow us to submit a duplicate proof if we observe 2 data shreds with differing merkle roots.

Copy link
Contributor

@behzadnouri behzadnouri Oct 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • If you have 2 data shreds with the same index and they have different merkle roots, then they already are identified as duplicate shreds regardless of their merkle root because their payload is different.
  • If they have different index and different merkle roots, then you can't determine if they belong to the same FEC set or not without receiving a coding shred from the same FEC set, because data shreds don't have the erasure set info.
    • But if you have a coding shred from the same FEC set, then the coding shred + one of the data shreds is already enough to prove mismatching merkle roots.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah you're right 🤦 i'll stick to the original approach of modifying the erasure meta instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If they have different index and different merkle roots, then you can't determine if they belong to the same FEC set or not without receiving a coding shred from the same FEC set

Out of curiosity, why is it not enough to compare (shred.slot(), shred.fec_set_index())?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed this offline.
@AshwinSekar is right. (shred.slot(), shred.fec_set_index()) will identify the FEC set.

The 2 cases below are left out but they can be tracked separately.

  • another scenario for duplicate blocks is that you receive a coding shred which indicates data shreds with indices [10..20] belong to the same FEC set with fec_set_index = 10, but then you have a data shred with index 17 (i.e. within that range) but different fec_set_index.
  • Another case is that we have 2 coding shreds which indicate overlapping FEC sets.

@@ -1227,6 +1245,39 @@ impl TypedColumn for columns::OptimisticSlots {
type Type = blockstore_meta::OptimisticSlotMetaVersioned;
}

impl Column for columns::MerkleRoot {
Copy link
Contributor Author

@AshwinSekar AshwinSekar Oct 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a copypasta from ShredCode, ShredData, and ErasureMeta. Happy to consolidate but am unsure about the effects of

 fn as_index(slot: Slot) -> Self::Index {
        (slot, 0)
    }

Is it more beneficial to cache a fec_set_index and use it instead of 0 here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you have for as_index() is fine; see this comment in the trail declaration:

// This trait method is primarily used by `Database::delete_range_cf()`, and is therefore only
// relevant for columns keyed by Slot: ie. SlotColumns and columns that feature a Slot as the
// first item in the key.
fn as_index(slot: Slot) -> Self::Index;

And yeah, looks like you might be able to reuse some impl's

Copy link
Contributor

@steviez steviez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I think you have things plumbed correctly everywhere (metrics, cleanup, etc). What are you thinking in terms of rolling this broader change out? I see this PR adds a getter/setter, but it is not actually plugged in anywhere yet. Would the actual meat of the logic be added later ?

As mentioned on Discord, we ideally have a minimal change that we can backport for the sake of compatibility between versions; is that this PR?

Also, what happens to the old ErasureMeta column; would this change essentially make that column obsolete ?

@AshwinSekar
Copy link
Contributor Author

As mentioned on Discord, we ideally have a minimal change that we can backport for the sake of compatibility between versions; is that this PR?

Also, what happens to the old ErasureMeta column; would this change essentially make that column obsolete ?

Was trying to be smart and avoid having to change the ErasureMeta column, but as behzad pointed out this doesn't work. I'll follow the original plan mentioned in Discord instead and have a minimal change that we can backport.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants