-
Notifications
You must be signed in to change notification settings - Fork 42
block component: verify and ingest finalization certs from footer #693
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
base: master
Are you sure you want to change the base?
Conversation
a1a080a to
9f437fb
Compare
| bank: Arc<Bank>, | ||
| parent_bank: Arc<Bank>, | ||
| marker: VersionedBlockMarker, | ||
| finalization_cert_sender: Option<&Sender<ConsensusMessage>>, |
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 optional (similar to replay_vote_sender in TowerBFT) because we don't need it for startup blocks
| /// `VoteType`s that contribute to this certificate. | ||
| /// | ||
| /// Must be in sync with `Vote::to_cert_types` | ||
| pub const fn limits_and_vote_types(&self) -> (Fraction, &'static [VoteType]) { |
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.
just moved these over from votor::common to here
| pub enum HighestFinalizedSlotCert { | ||
| /// Standard finalization: requires both a Finalize cert and a Notarize cert for the same slot | ||
| #[allow(clippy::large_enum_variant)] | ||
| pub enum BlockFinalization { |
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.
open to naming suggestions
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 might be tempted to to add a Cert suffix otherwise this is definitely an improvement.
akhi3030
left a comment
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.
Generally looks good. Minor comments really. It would've been easier to review if the PR was done in parts e.g. removal of Arc and renaming, etc. being done separately.
entry/src/block_component.rs
Outdated
|
|
||
| /// Converts the block marker representation of a finalization certificate into verification friendly | ||
| /// representation of Slow or Fast finalization certificates | ||
| pub fn to_certificates(self) -> Result<BlockFinalization, BlsError> { |
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.
if this fails, we will get a generic bls error that will not explain which verification failed. Might make things hard to debug from logs.
|
|
||
| let final_certs = final_cert | ||
| .to_certificates() | ||
| .map_err(|_| BlockComponentProcessorError::InvalidFinalizationCertificate)?; |
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.
if we return a more informed error here then this might have to be updated. I think just printing out the error in the warn would suffice.
entry/src/block_component.rs
Outdated
|
|
||
| /// Converts the block marker representation of a finalization certificate into verification friendly | ||
| /// representation of Slow or Fast finalization certificates | ||
| pub fn to_certificates(self) -> Result<BlockFinalization, BlsError> { |
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: since we are consuming self, the function should be called into_....
| .to_certificates() | ||
| .map_err(|_| BlockComponentProcessorError::InvalidFinalizationCertificate)?; | ||
|
|
||
| match &final_certs { |
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: I wonder if this verification can be moved into to_certificates() so that we cannot even construct BlockFinalization unless all the checks pass and then we do not have to worry about whether or not such checks were performed when we are using a object of type BlockFinalization. Bonus points for using a new type e.g. ValidatedBlockFinalization 😄
| finalize_cert, | ||
| notarize_cert, | ||
| } => { | ||
| let _ = sender.send(ConsensusMessage::from(notarize_cert)); |
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.
should we print a warn if this fails to help with debugging? If someone changes the unbounded or the receiver is disconnected, we would at least capture some logs.
| pub enum HighestFinalizedSlotCert { | ||
| /// Standard finalization: requires both a Finalize cert and a Notarize cert for the same slot | ||
| #[allow(clippy::large_enum_variant)] | ||
| pub enum BlockFinalization { |
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 might be tempted to to add a Cert suffix otherwise this is definitely an improvement.
| pub fn slot(&self) -> Slot { | ||
| match self { | ||
| HighestFinalizedSlotCert::Finalize { | ||
| BlockFinalization::Finalize { |
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.
| BlockFinalization::Finalize { | |
| Self::Finalize { |
So we do not have to update this in case of renaming.
9f437fb to
07357a2
Compare
656763a to
2a2de5e
Compare
Excellent suggestion, this makes the code a lot easier to look at and lets me encapsulate all the deserialize and verification logic. Should be good for another look, and apologies for how long this PR is, it got out of hand as I was writing it. |
2a2de5e to
ed10697
Compare
ed10697 to
cac24be
Compare
akhi3030
left a comment
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.
thanks, looks much better. Just a couple of small comments now.
| /// This type can only be constructed through validation methods, providing | ||
| /// compile-time guarantees that the contained certificates are valid. |
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.
Unfortunately, since this is an enum, this can be constructed directly. E.g. the compiler will let us just do let foo = ValidatedBlockFinalizationCert::FastFinalize(...);.
The way to get this guarantee is to turn this into a struct. Maybe we can define it as:
struct ValidatedBlockFinalizationCert {
finalize_cert: Certificate,
notar_cert: Option<Certificate>,
}
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 a really good point, I do like keeping the enum instead of having the option. I hid it in an inner type here c903a11 seems like an idiomatic approach
| } | ||
| } | ||
|
|
||
| fn verify_certificate( |
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.
could you add some doc comments to explain what is being returned in the u64s please?
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 7e0b411
| /// - BLS signature conversion fails | ||
| /// - Certificate signature verification fails | ||
| /// - The certificates don't meet the required stake thresholds | ||
| pub fn try_from_footer( |
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.
It is fine to defer it for now but we should add some unit tests to ensure that this function does fail for invalid certs.
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.
ah I did have some basic unit tests but forgot to move them over, done here 7acac02
| "Received a slow finalization in the footer for slot {slot} block_id \ | ||
| {block_id:?} in bank slot {} with notarize {notarize_percent} stake \ | ||
| expecting at least {notarize_threshold}", | ||
| bank.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.
should we take the slot from the footer instead of the bank here? Given the call tree, they should match up but it isn't clear in this function that that will always be the case.
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 footer itself doesn't have a slot.
Here we log both the finalization cert slot and the bank slot.
core/src/block_creation_loop.rs
Outdated
|
|
||
| BlockComponentProcessor::update_bank_with_footer( | ||
| working_bank.bank.clone_without_scheduler(), | ||
| &working_bank.bank.clone_without_scheduler(), |
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: we are taking a reference to a cloned object. Could this just be &working_bank.bank?
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.
good catch 1c4c67d
akhi3030
left a comment
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
Problem
We need to verify the slow / fast finalization certificates from the block footer and ingest it into our consensus pool.
Ingestion here is key for unstaked nodes.
Summary of Changes
HighestFinalizedSlotCert->BlockFinalizationsince this is used both in the consensus pool to track highest finalized block and for extraction of the footerArcfromBlockFinalization, copying should be cheap enough ~ once every 400ms