-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
[Perf] Avoid fetching already seen Certificates #3439
Open
vicsn
wants to merge
2
commits into
AleoNet:staging
Choose a base branch
from
ProvableHQ:reduce_fetching_overhead
base: staging
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -916,9 +916,18 @@ impl<N: Network> Primary<N> { | |
peer_ip: SocketAddr, | ||
certificate: BatchCertificate<N>, | ||
) -> Result<()> { | ||
// Ensure the batch certificate is from an authorized validator. | ||
if !self.gateway.is_authorized_validator_ip(peer_ip) { | ||
// Proceed to disconnect the validator. | ||
self.gateway.disconnect(peer_ip); | ||
bail!("Malicious peer - Received a batch certificate from an unauthorized validator IP ({peer_ip})"); | ||
} | ||
// Ensure storage does not already contain the certificate. | ||
if self.storage.contains_certificate(certificate.id()) { | ||
return Ok(()); | ||
// Otherwise, ensure ephemeral storage contains the certificate. | ||
} else if !self.storage.contains_unprocessed_certificate(certificate.id()) { | ||
self.storage.insert_unprocessed_certificate(certificate.clone())?; | ||
} | ||
|
||
// Retrieve the batch certificate author. | ||
|
@@ -928,12 +937,6 @@ impl<N: Network> Primary<N> { | |
// Retrieve the batch certificate committee ID. | ||
let committee_id = certificate.committee_id(); | ||
|
||
// Ensure the batch certificate is from an authorized validator. | ||
if !self.gateway.is_authorized_validator_ip(peer_ip) { | ||
// Proceed to disconnect the validator. | ||
self.gateway.disconnect(peer_ip); | ||
bail!("Malicious peer - Received a batch certificate from an unauthorized validator IP ({peer_ip})"); | ||
} | ||
// Ensure the batch certificate is not from the current primary. | ||
if self.gateway.account().address() == author { | ||
bail!("Received a batch certificate for myself ({author})"); | ||
|
@@ -947,10 +950,8 @@ impl<N: Network> Primary<N> { | |
|
||
// Retrieve the committee lookback. | ||
let committee_lookback = self.ledger.get_committee_lookback_for_round(certificate_round)?; | ||
// Retrieve the certificates. | ||
let certificates = self.storage.get_certificates_for_round(certificate_round); | ||
// Construct a set over the authors. | ||
let authors = certificates.iter().map(BatchCertificate::author).collect(); | ||
// Retrieve the certificate authors. | ||
let authors = self.storage.get_certificate_authors_for_round(certificate_round); | ||
// Check if the certificates have reached the quorum threshold. | ||
let is_quorum = committee_lookback.is_quorum_threshold_reached(&authors); | ||
|
||
|
@@ -1027,13 +1028,13 @@ impl<N: Network> Primary<N> { | |
if current_round == 0 { | ||
break; | ||
} | ||
// Retrieve the certificates. | ||
let certificates = self_.storage.get_certificates_for_round(current_round); | ||
// Retrieve the primary certificate. | ||
certificate = | ||
certificates.into_iter().find(|certificate| certificate.author() == primary_address); | ||
// Retrieve the primary certificates. | ||
if let Some(primary_certificate) = | ||
self_.storage.get_certificate_for_round_with_author(current_round, primary_address) | ||
{ | ||
certificate = Some(primary_certificate); | ||
// If the primary certificate was not found, decrement the round. | ||
if certificate.is_none() { | ||
} else { | ||
current_round = current_round.saturating_sub(1); | ||
} | ||
} | ||
|
@@ -1210,17 +1211,16 @@ impl<N: Network> Primary<N> { | |
let next_round = self_.current_round().saturating_add(1); | ||
// Determine if the quorum threshold is reached for the current round. | ||
let is_quorum_threshold_reached = { | ||
// Retrieve the certificates for the next round. | ||
let certificates = self_.storage.get_certificates_for_round(next_round); | ||
// Retrieve the certificate authors for the next round. | ||
let authors = self_.storage.get_certificate_authors_for_round(next_round); | ||
// If there are no certificates, then skip this check. | ||
if certificates.is_empty() { | ||
if authors.is_empty() { | ||
continue; | ||
} | ||
let Ok(committee_lookback) = self_.ledger.get_committee_lookback_for_round(next_round) else { | ||
warn!("Failed to retrieve the committee lookback for round {next_round}"); | ||
continue; | ||
}; | ||
let authors = certificates.iter().map(BatchCertificate::author).collect(); | ||
committee_lookback.is_quorum_threshold_reached(&authors) | ||
}; | ||
// Attempt to increment to the next round if the quorum threshold is reached. | ||
|
@@ -1541,8 +1541,7 @@ impl<N: Network> Primary<N> { | |
|
||
// Determine if quorum threshold is reached on the batch round. | ||
let is_quorum_threshold_reached = { | ||
let certificates = self.storage.get_certificates_for_round(batch_round); | ||
let authors = certificates.iter().map(BatchCertificate::author).collect(); | ||
let authors = self.storage.get_certificate_authors_for_round(batch_round); | ||
let committee_lookback = self.ledger.get_committee_lookback_for_round(batch_round)?; | ||
committee_lookback.is_quorum_threshold_reached(&authors) | ||
}; | ||
|
@@ -1668,14 +1667,23 @@ impl<N: Network> Primary<N> { | |
) -> Result<HashSet<BatchCertificate<N>>> { | ||
// Initialize a list for the missing certificates. | ||
let mut fetch_certificates = FuturesUnordered::new(); | ||
// Initialize a set for the missing certificates. | ||
let mut missing_certificates = HashSet::default(); | ||
// Iterate through the certificate IDs. | ||
for certificate_id in certificate_ids { | ||
// Check if the certificate already exists in the ledger. | ||
if self.ledger.contains_certificate(certificate_id)? { | ||
continue; | ||
} | ||
// If we do not have the certificate, request it. | ||
if !self.storage.contains_certificate(*certificate_id) { | ||
// Check if the certificate already exists in storage. | ||
if self.storage.contains_certificate(*certificate_id) { | ||
continue; | ||
} | ||
// If we have not fully processed the certificate yet, store it. | ||
if let Some(certificate) = self.storage.get_unprocessed_certificate(*certificate_id) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NOTE: we can additionally resolve any outstanding certificate requests for this particular certificate. |
||
missing_certificates.insert(certificate); | ||
} else { | ||
// If we do not have the certificate, request it. | ||
trace!("Primary - Found a new certificate ID for round {round} from '{peer_ip}'"); | ||
// TODO (howardwu): Limit the number of open requests we send to a peer. | ||
// Send an certificate request to the peer. | ||
|
@@ -1692,8 +1700,6 @@ impl<N: Network> Primary<N> { | |
), | ||
} | ||
|
||
// Initialize a set for the missing certificates. | ||
let mut missing_certificates = HashSet::with_capacity(fetch_certificates.len()); | ||
// Wait for all of the missing certificates to be fetched. | ||
while let Some(result) = fetch_certificates.next().await { | ||
// Insert the missing certificate into the set. | ||
|
@@ -2058,8 +2064,7 @@ mod tests { | |
store_certificate_chain(&primary, &accounts, round, &mut rng); | ||
|
||
// Get transmissions from previous certificates. | ||
let previous_certificate_ids: IndexSet<_> = | ||
primary.storage.get_certificates_for_round(prev_round).iter().map(|cert| cert.id()).collect(); | ||
let previous_certificate_ids: IndexSet<_> = primary.storage.get_certificate_ids_for_round(prev_round); | ||
|
||
// Track the number of transmissions in the previous round. | ||
let mut num_transmissions_in_previous_round = 0; | ||
|
@@ -2602,8 +2607,7 @@ mod tests { | |
store_certificate_chain(&primary, &accounts, round, &mut rng); | ||
|
||
// Get transmissions from previous certificates. | ||
let previous_certificate_ids: IndexSet<_> = | ||
primary.storage.get_certificates_for_round(prev_round).iter().map(|cert| cert.id()).collect(); | ||
let previous_certificate_ids: IndexSet<_> = primary.storage.get_certificate_ids_for_round(prev_round); | ||
|
||
// Generate a solution and a transaction. | ||
let (solution_commitment, solution) = sample_unconfirmed_solution(&mut rng); | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 is the certificate not removed from the
unprocessed_certificates
cache when this function is completed?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 removed from the cache if the certificate is inserted into storage, so even sooner than waiting for the function to complete.
You might wonder whether a malicious validator could fill up the cache, and they could. The cache helps in the optimistic case to speed up processing.