-
Notifications
You must be signed in to change notification settings - Fork 180
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
Separate recent hashed values cache into separate types #2902
Conversation
linera-chain/src/manager.rs
Outdated
} | ||
|
||
// TODO: Is it guaranteed that if key_pair = None, then the vote is not signed ever? |
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 want to bring reviewers' attention to this - i checked but want to confirm
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.
Yes, these should only ever contain votes we signed with key_pair
, and only if that's Some
. (That invariant should, in fact, be guaranteed just by this module alone. Edit: It isn't, strictly speaking, since the fields are public.)
/// If the `value` is a [`HashedCertificateValue::ValidatedBlock`], its respective | ||
/// [`HashedCertificateValue::ConfirmedBlock`] is also cached. | ||
pub async fn insert<'a>(&self, value: Cow<'a, HashedCertificateValue>) -> bool { | ||
pub async fn insert<'a>(&self, value: Cow<'a, Hashed<T>>) -> bool { |
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.
Want to emphasize that we no longer insert a validated variant of the hashed value if the confirmed one is being inserted.
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 was the other way round, I think?)
If I'm reading this correctly we are inserting the confirmed variant when we sign it; that should still take care of the most common case, so that most validators that receive a lite confirmed block certificate will already have its value in the cache.
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.
Yes yes, it was the other way around.
let pending = manager | ||
.confirmed_vote | ||
.as_ref() | ||
.map(|vote| vote.lite()) | ||
.or_else(move || manager.validated_vote.as_ref().map(|vote| vote.lite())); |
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.
Also this - it shouldn't happen that both confirmed_vote
and validated_vote
are both set to Some(_)
at the same time.
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 looks like you made sure of that everywhere.
Alternatively, we could avoid explicitly setting them to None
and always prefer the highest-round vote, with the confirmed one taking precedence.
/// Test that insertion of a validated block certificate also inserts its respective confirmed | ||
/// block certificate. | ||
#[tokio::test] | ||
async fn test_insertion_of_validated_also_inserts_confirmed() { |
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.
Tests were removed but there's an issue now to bring back similar functionality #2912
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.
Makes sense to me; most of these seem to be related to the "validated vs. confirmed" logic. (cc @jvff)
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 blockers from my side; but the TODO
question needs to be removed from the code, of course.
linera-chain/src/certificate/lite.rs
Outdated
@@ -74,12 +74,11 @@ impl<'a> LiteCertificate<'a> { | |||
} | |||
|
|||
/// Returns the `Certificate` with the specified value, if it matches. |
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.
/// Returns the `Certificate` with the specified value, if it matches. | |
/// Returns the [`GenericCertificate`] with the specified value, if it matches. |
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 in Fix comments
linera-chain/src/manager.rs
Outdated
} | ||
|
||
// TODO: Is it guaranteed that if key_pair = None, then the vote is not signed ever? |
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.
Yes, these should only ever contain votes we signed with key_pair
, and only if that's Some
. (That invariant should, in fact, be guaranteed just by this module alone. Edit: It isn't, strictly speaking, since the fields are public.)
} | ||
|
||
/// Verifies the safety of a proposed block with respect to voting rules. |
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 not?
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.
You mean why I removed the comment? probably by mistake.
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 in 2cfad93
} | ||
if let Some(Vote { value, round, .. }) = &self.confirmed_vote { | ||
if value.inner().inner().block == *new_block && *round == new_round { | ||
return Ok(Outcome::Skip); // We already voted to confirm this 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.
Now I'm wondering if we're missing a check in this function that, regardless of locked block or votes, the certificate is from at least the current round.
I created #2914 for it.
HashedCertificateValue::new_confirmed(executed_block) | ||
.try_into() | ||
.expect("ConfirmedBlock"), |
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.
We could have a more direct constructor for that now.
@@ -250,7 +250,7 @@ async fn test_application_permissions() { | |||
let value = HashedCertificateValue::new_confirmed(outcome.with(valid_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.
Here we could also start using the new type right away.
/// If the `value` is a [`HashedCertificateValue::ValidatedBlock`], its respective | ||
/// [`HashedCertificateValue::ConfirmedBlock`] is also cached. | ||
pub async fn insert<'a>(&self, value: Cow<'a, HashedCertificateValue>) -> bool { | ||
pub async fn insert<'a>(&self, value: Cow<'a, Hashed<T>>) -> bool { |
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 was the other way round, I think?)
If I'm reading this correctly we are inserting the confirmed variant when we sign it; that should still take care of the most common case, so that most validators that receive a lite confirmed block certificate will already have its value in the cache.
/// Test that insertion of a validated block certificate also inserts its respective confirmed | ||
/// block certificate. | ||
#[tokio::test] | ||
async fn test_insertion_of_validated_also_inserts_confirmed() { |
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.
Makes sense to me; most of these seem to be related to the "validated vs. confirmed" logic. (cc @jvff)
@@ -331,7 +333,7 @@ where | |||
} | |||
.with(block), | |||
); | |||
make_certificate(committee, worker, value) | |||
make_certificate(committee, worker, value.try_into().expect("Confirmed 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.
Here we should also be able to avoid the expect
, using the appropriate constructor.
Even if inside that constructor we still expect
for now (but I hope we can remove that entirely soon) it would at least clean up all the call sites.
(But maybe that's something for another PR. 🤷)
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.
Yes, let's leave it for a separate PR - I'm currently in the process of removing a lot of HashedCertificateValue
usage and maybe it'll go away entirely soon.
Done |
Motivation
Part of the epic to remove
CertificateValue
and be able to statically determine a type of value the certificate is for.Proposal
Replace
ChainManager::pending
with two separate fields -confirmed_vote
andvalidated_vote
. When one of the votes is inserted, the other is cleared so that only one of the fields is ever populated.Test Plan
CI should catch any regressions.
Release Plan
Links
Closes #2897