-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
adds chained merkle shreds variant #34787
adds chained merkle shreds variant #34787
Conversation
9c3587f
to
836ede2
Compare
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #34787 +/- ##
===========================================
+ Coverage 0 81.7% +81.7%
===========================================
Files 0 826 +826
Lines 0 223324 +223324
===========================================
+ Hits 0 182461 +182461
- Misses 0 40863 +40863 |
b5d567f
to
5f05e9f
Compare
e15abe6
to
3b31d6c
Compare
@@ -93,6 +93,7 @@ impl Shredder { | |||
self.version, | |||
self.reference_tick, | |||
is_last_in_slot, | |||
None, // chained_merkle_root |
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.
Following commits will do the plumbing here.
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.
for the first FEC set will we chain the merkle root from the last FEC set of the parent block?
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.
@AshwinSekar no real objection to do so (aside from slightly more code to look that up from blockstore),
but can you clarify the motivation to do so?
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.
essentially it gives us a unique identifier for a fork. this is useful for comparison if we add the merkle root to votes.
imagine we have some unplayed slot S in our blockstore and S gets confirmed through votes. we can easily compare S to the merkle root in the votes to verify that we have the correct version of S.
if we also chain the merkle root to the parent block, the same comparison will tell us if we have the correct version of S - 1, S -2, and such ancestors.
in the event that we have parent block P and child block C where the chaining of the first FEC set of C does not match the last FEC set of P, we can conclude that we have incompatible versions of P and C. Depending on which merkle root the votes for C or its descendants contain, we can reconcile the situation by dumping and repairing either P or C appropriately.
3b31d6c
to
df841cc
Compare
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.
Looks pretty good to me. Lots of eyeballing that size/offset calculations are functioning as intended, so we'll have to lean on testing
ci/do-audit.sh
Outdated
@@ -30,6 +30,7 @@ cargo_audit_ignores=( | |||
--ignore RUSTSEC-2023-0001 | |||
|
|||
--ignore RUSTSEC-2022-0093 | |||
--ignore RUSTSEC-2024-0003 |
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: This has been addressed upstream so you can rebase and remove this
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.
done.
df841cc
to
9f44a29
Compare
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.
LGTM. Should probably wait for others to weigh in as well
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.
Looks good!
let ShredVariant::MerkleCode(proof_size, chained) = self.common_header.shred_variant else { | ||
return Err(Error::InvalidShredVariant); | ||
}; | ||
Self::get_proof_offset(proof_size, chained) | ||
} | ||
|
||
fn get_proof_offset(proof_size: u8, chained: bool) -> Result<usize, Error> { | ||
Ok(Self::SIZE_OF_HEADERS | ||
+ Self::capacity(proof_size, chained)? | ||
+ if chained { SIZE_OF_MERKLE_ROOT } else { 0 }) | ||
} | ||
|
||
fn chained_merkle_root_offset(&self) -> Result<usize, Error> { | ||
let ShredVariant::MerkleCode(proof_size, /*chained:*/ true) = | ||
self.common_header.shred_variant | ||
else { | ||
return Err(Error::InvalidShredVariant); | ||
}; | ||
Self::get_proof_offset(proof_size) | ||
Ok(Self::SIZE_OF_HEADERS + Self::capacity(proof_size, /*chained:*/ true)?) | ||
} | ||
|
||
fn chained_merkle_root(&self) -> Result<Hash, Error> { | ||
let offset = self.chained_merkle_root_offset()?; | ||
self.payload | ||
.get(offset..offset + SIZE_OF_MERKLE_ROOT) | ||
.map(Hash::new) | ||
.ok_or(Error::InvalidPayloadSize(self.payload.len())) | ||
} | ||
|
||
fn get_proof_offset(proof_size: u8) -> Result<usize, Error> { | ||
Ok(Self::SIZE_OF_HEADERS + Self::capacity(proof_size)?) | ||
fn set_chained_merkle_root(&mut self, chained_merkle_root: &Hash) -> Result<(), Error> { | ||
let offset = self.chained_merkle_root_offset()?; | ||
let Some(buffer) = self.payload.get_mut(offset..offset + SIZE_OF_MERKLE_ROOT) else { | ||
return Err(Error::InvalidPayloadSize(self.payload.len())); | ||
}; | ||
buffer.copy_from_slice(chained_merkle_root.as_ref()); | ||
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.
The worst type of code to write + review, but seems right 😃
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.
In what sense?
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.
the tedium of having to remember where all the offsets are haha
let ShredVariant::MerkleData(proof_size, chained) = self.common_header.shred_variant else { | ||
return Err(Error::InvalidShredVariant); | ||
}; | ||
let offset = Self::SIZE_OF_HEADERS + Self::capacity(proof_size, chained)?; |
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.
Is this calculation still equivalent to calling self.proof_offset()?
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.
no. the chained merkle root is not part of the erasure coding.
so if the shred is chained, then proof_offset would be 32 bytes past the offset calculated here.
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.
no. the chained merkle root is not part of the erasure coding
Ah yeah, thats the critical part here, thanks.
With the new variants, each Merkle shred will also include the Merkle root of the previous erasure batch.
9f44a29
to
66d69c9
Compare
Problem
Harden shreds spec.
Summary of Changes
With the new variants, each Merkle shred will also include the Merkle
root of the previous erasure batch.