-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
blockstore: populate duplicate shred proofs for merkle root conflicts #34270
blockstore: populate duplicate shred proofs for merkle root conflicts #34270
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #34270 +/- ##
========================================
Coverage 81.8% 81.8%
========================================
Files 824 824
Lines 222261 222327 +66
========================================
+ Hits 181887 182009 +122
+ Misses 40374 40318 -56 |
f1d368d
to
58802c3
Compare
58802c3
to
e9a174a
Compare
e9a174a
to
5b986db
Compare
82ac70c
to
c0e3f85
Compare
ledger/src/blockstore.rs
Outdated
if let Some(shred) = just_inserted_shreds.get(&key) { | ||
Cow::Borrowed(shred.payload()) | ||
} else { | ||
} else if shred_type == ShredType::Data { |
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 use a match
expression here?
This code is not safe if ShredType
enum is extended with a new variant. (unlikely that it happens but no reason to leave this foot gun here).
ledger/src/blockstore.rs
Outdated
self.get_coding_shred(slot, u64::from(index)) | ||
.unwrap() | ||
.unwrap_or_else(|| { | ||
panic!("{} {} {:?} must be present!", slot, index, shred_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.
What ensures that the shred is present here?
This is a pretty risky method that internally relies on certain presumptions where the caller may not be aware of.
I do see the logic was already present before this commit, but the commit is extending the uses of this method.
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.
Nothing. This method is used for cases where a meta structure has already informed you of the shreds existence, where it is preferable to panic if there is an inconsistency.
However if you prefer I can return an option, and have the callers error!
and continue instead.
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, I think returning an Option
is better here. Maybe in a separate pr first if that is changing too much of existing code.
this function as it stands is a pretty risky code.
ledger/src/blockstore.rs
Outdated
slot: Slot, | ||
index: u64, | ||
index: u32, | ||
shred_type: ShredType, |
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 just take a ShredId
instead of these 3 arguments?
169f8ce
to
38a4e8d
Compare
4e73705
to
0c05052
Compare
0c05052
to
ffc9039
Compare
core/src/window_service.rs
Outdated
let send_merkle_root_conflicts = cluster_nodes::check_feature_activation( | ||
&feature_set::merkle_conflict_duplicate_proofs::id(), |
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 is using two different names to refer to the same thing,
send_merkle_root_conflicts
merkle_conflict_duplicate_proofs
Can we use the same name for the feature and the flag, so that it is easier to find all the instances?
// Although this proof can be immediately stored on detection, we wait until | ||
// here in order to check the feature flag, as storage in blockstore can | ||
// preclude the detection of other duplicate proofs in this slot |
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 blockstore doesn't check the feature flag before sending this?
ledger/src/blockstore.rs
Outdated
// A previous shred has been inserted in this batch or in blockstore | ||
// Compare our current shred against the previous shred for potential | ||
// conflicts | ||
if !self.perform_merkle_check( |
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.
perform_merkle_check
is a pretty confusing name and error prone.
Like by no means it is clear if false
is good or bad.
ledger/src/blockstore.rs
Outdated
self.get_coding_shred(slot, u64::from(index)) | ||
.unwrap() | ||
.unwrap_or_else(|| { | ||
panic!("{} {} {:?} must be present!", slot, index, shred_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.
yeah, I think returning an Option
is better here. Maybe in a separate pr first if that is changing too much of existing code.
this function as it stands is a pretty risky code.
ledger/src/blockstore.rs
Outdated
/// Returns true if there is no merkle root conflict between | ||
/// the existing `merkle_root_meta` and `shred` | ||
/// | ||
/// Otherwise return false and if not already present, add duplicate proof to | ||
/// `duplicate_shreds`. | ||
fn perform_merkle_check( |
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.
need a better name to be more clear what true
or false
means at the call site without having to look up this comment. otherwise the usage will be very error prone.
ledger/src/blockstore.rs
Outdated
merkle_root_meta.merkle_root(), | ||
merkle_root_meta.first_received_shred_index(), | ||
merkle_root_meta.first_received_shred_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.
can we just {:?}
the merkle_root_meta
instead of these 3 lines?
shred: &Shred, | ||
duplicate_shreds: &mut Vec<PossibleDuplicateShred>, | ||
) -> bool { | ||
let new_merkle_root = shred.merkle_root().ok(); |
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 don't we check for the feature_set::merkle_conflict_duplicate_proofs
feature activation here in this function?
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 also considered this as an option - since this is code is temporary until the feature flag is turned on I went with this approach to keep the PR small.
There are 183 calls (mostly all testing code) for blockstore.insert_shreds
that we would need to be altered and then removed on feature flag cleanup.
I figured it would be easiest to check the feature flag in window_service
and once the feature flag has been activated move the blockstore.store_duplicate_slot
from window_service
to blockstore.insert_shreds
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.
fine, if there is no correctness concern.
e.g. when blockstore returns a duplicate proof it will stop processing there and ignores other variants of duplicate proofs.
But if window-service ignores that because the feature is not activated, then it is possible that the other variants of duplicates proofs were also present but not processed.
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.
since we don't insert into blockstore until window service, other variants of duplicate proofs will not be precluded from being processed if the feature flag is not present.
additionally because they are separate enum variants, multiple signals can be sent to window service if a block violates multiple duplicate conditions.
ffc9039
to
bf6fea9
Compare
Problem
We only construct duplicate proofs for conflicting shreds, LAST_SHRED_IN_SLOT, and erasure meta conflicts.
Summary of Changes
When receiving a new shred check to see if there is a merkle root conflict from an existing merkle root meta. If there is such a conflict, construct a duplicate proof and notify gossip and the duplicate block state machine.
Split from #33889
Fixes #33644