Skip to content
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

Merged
merged 9 commits into from
Nov 19, 2024

Conversation

deuszx
Copy link
Contributor

@deuszx deuszx commented Nov 15, 2024

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 and validated_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

  • Nothing to do / These changes follow the usual release cycle.

Links

Closes #2897

}

// TODO: Is it guaranteed that if key_pair = None, then the vote is not signed ever?
Copy link
Contributor Author

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

Copy link
Contributor

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 {
Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

@deuszx deuszx requested review from ma2bd, afck and bart-linera November 15, 2024 16:08
@deuszx deuszx marked this pull request as ready for review November 15, 2024 16:09
Comment on lines +648 to +652
let pending = manager
.confirmed_vote
.as_ref()
.map(|vote| vote.lite())
.or_else(move || manager.validated_vote.as_ref().map(|vote| vote.lite()));
Copy link
Contributor Author

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.

Copy link
Contributor

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() {
Copy link
Contributor Author

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

Copy link
Contributor

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)

Copy link
Contributor

@afck afck left a 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.

@@ -74,12 +74,11 @@ impl<'a> LiteCertificate<'a> {
}

/// Returns the `Certificate` with the specified value, if it matches.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Returns the `Certificate` with the specified value, if it matches.
/// Returns the [`GenericCertificate`] with the specified value, if it matches.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in Fix comments

}

// TODO: Is it guaranteed that if key_pair = None, then the vote is not signed ever?
Copy link
Contributor

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.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not?

Copy link
Contributor Author

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.

Copy link
Contributor Author

@deuszx deuszx Nov 19, 2024

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.
Copy link
Contributor

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.

Comment on lines +443 to +445
HashedCertificateValue::new_confirmed(executed_block)
.try_into()
.expect("ConfirmedBlock"),
Copy link
Contributor

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));
Copy link
Contributor

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.

linera-core/src/chain_worker/actor.rs Show resolved Hide resolved
/// 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 {
Copy link
Contributor

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() {
Copy link
Contributor

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"))
Copy link
Contributor

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. 🤷)

Copy link
Contributor Author

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.

@deuszx
Copy link
Contributor Author

deuszx commented Nov 19, 2024

No blockers from my side; but the TODO question needs to be removed from the code, of course.

Done

@deuszx deuszx merged commit 12e99a5 into main Nov 19, 2024
21 checks passed
@deuszx deuszx deleted the chain-manager-pending-split branch November 19, 2024 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Replace pending field in ChainManager with two seperate ones - for validated and confirmed votes
2 participants