Skip to content
This repository has been archived by the owner on Feb 19, 2024. It is now read-only.

Commit

Permalink
Performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
dhedey committed Jun 3, 2022
1 parent 82e85ab commit f381a31
Showing 1 changed file with 44 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,19 @@
import com.radixdlt.hotstuff.bft.View;
import com.radixdlt.hotstuff.liveness.VoteTimeout;
import com.radixdlt.hotstuff.safety.SafetyState.Builder;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/** Manages safety of the protocol. */
public final class SafetyRules {
private static final Logger logger = LogManager.getLogger();

private static final int VERIFIED_CERTIFICATES_CACHE_MAX_SIZE = 1000;

private final BFTNode self;
private final Hasher hasher;
private final HashSigner signer;
Expand All @@ -102,6 +106,7 @@ public final class SafetyRules {
private final PersistentSafetyStateStore persistentSafetyStateStore;

private SafetyState state;
private final Set<HashCode> verifiedCertificatesCache = new LinkedHashSet<>();

@Inject
public SafetyRules(
Expand Down Expand Up @@ -261,6 +266,12 @@ && verifyQcAgainstTheValidatorSet(highQC.highestCommittedQC())
}

public boolean verifyQcAgainstTheValidatorSet(QuorumCertificate qc) {
final var qcHash = hasher.hash(qc);

if (verifiedCertificatesCache.contains(qcHash)) {
return true;
}

if (isGenesisQc(qc)) {
// A genesis QC doesn't require any signatures
return true;
Expand All @@ -280,7 +291,22 @@ public boolean verifyQcAgainstTheValidatorSet(QuorumCertificate qc) {
validationState.addSignature(
e.getKey(), e.getValue().timestamp(), e.getValue().signature()));

return allSignaturesAddedSuccessfully && validationState.complete();
final var isQcValid = allSignaturesAddedSuccessfully && validationState.complete();

if (isQcValid) {
addVerifiedCertificateToCache(qcHash);
}

return isQcValid;
}

private void addVerifiedCertificateToCache(HashCode certificateHash) {
if (verifiedCertificatesCache.size() >= VERIFIED_CERTIFICATES_CACHE_MAX_SIZE) {
final var iter = verifiedCertificatesCache.iterator();
iter.next();
iter.remove();
}
verifiedCertificatesCache.add(certificateHash);
}

private boolean isGenesisQc(QuorumCertificate qc) {
Expand All @@ -297,7 +323,7 @@ private boolean isGenesisQc(QuorumCertificate qc) {

private boolean areAllQcTimestampedSignaturesValid(QuorumCertificate qc) {
final var voteData = qc.getVoteData();
return qc.getTimestampedSignatures().getSignatures().entrySet().stream()
return qc.getTimestampedSignatures().getSignatures().entrySet().parallelStream()
.allMatch(
e -> {
final var nodePublicKey = e.getKey().getKey();
Expand All @@ -307,14 +333,27 @@ private boolean areAllQcTimestampedSignaturesValid(QuorumCertificate qc) {
}

public boolean verifyTcAgainstTheValidatorSet(TimeoutCertificate tc) {
return tc.getSigners().allMatch(validatorSet::containsNode)
&& areAllTcTimestampedSignaturesValid(tc);
final var tcHash = hasher.hash(tc);

if (verifiedCertificatesCache.contains(tcHash)) {
return true;
}

final var isTcValid =
tc.getSigners().allMatch(validatorSet::containsNode)
&& areAllTcTimestampedSignaturesValid(tc);

if (isTcValid) {
addVerifiedCertificateToCache(tcHash);
}

return isTcValid;
}

private boolean areAllTcTimestampedSignaturesValid(TimeoutCertificate tc) {
final var voteTimeout = new VoteTimeout(tc.getView(), tc.getEpoch());
final var voteTimeoutHash = hasher.hash(voteTimeout);
return tc.getTimestampedSignatures().getSignatures().entrySet().stream()
return tc.getTimestampedSignatures().getSignatures().entrySet().parallelStream()
.allMatch(
e -> {
final var nodePublicKey = e.getKey().getKey();
Expand Down

0 comments on commit f381a31

Please sign in to comment.