Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

RoundChangeCertificateValidator requires unique authors #989

Merged
merged 7 commits into from
Feb 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public boolean validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot(
final Collection<SignedData<RoundChangePayload>> roundChangeMsgs =
roundChangeCert.getRoundChangePayloads();

if (hasDuplicateAuthors(roundChangeMsgs)) {
return false;
}

if (roundChangeMsgs.size() < quorum) {
LOG.info("Invalid RoundChangeCertificate, insufficient RoundChange messages.");
return false;
Expand All @@ -84,6 +88,18 @@ public boolean validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot(
return true;
}

private boolean hasDuplicateAuthors(
final Collection<SignedData<RoundChangePayload>> roundChangeMsgs) {
final long distinctAuthorCount =
roundChangeMsgs.stream().map(SignedData::getAuthor).distinct().count();

if (distinctAuthorCount != roundChangeMsgs.size()) {
LOG.info("Invalid RoundChangeCertificate, multiple RoundChanges from the same author.");
return true;
}
return false;
}

public boolean validateProposalMessageMatchesLatestPrepareCertificate(
final RoundChangeCertificate roundChangeCert, final Block proposedBlock) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package tech.pegasys.pantheon.consensus.ibft.validation;

import static java.util.Collections.singletonList;
import static java.util.Optional.empty;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -84,9 +85,9 @@ public void roundChangeMessagesDoNotAllTargetRoundFails() {

final RoundChangeCertificate.Builder roundChangeBuilder = new RoundChangeCertificate.Builder();
roundChangeBuilder.appendRoundChangeMessage(
proposerMessageFactory.createRoundChange(roundIdentifier, Optional.empty()));
proposerMessageFactory.createRoundChange(roundIdentifier, empty()));
roundChangeBuilder.appendRoundChangeMessage(
proposerMessageFactory.createRoundChange(prevRound, Optional.empty()));
proposerMessageFactory.createRoundChange(prevRound, empty()));

assertThat(
validator.validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot(
Expand All @@ -104,8 +105,7 @@ public void invalidPrepareMessageInOnePrepareCertificateFails() {
roundIdentifier,
Optional.of(
new PreparedRoundArtifacts(
proposerMessageFactory.createProposal(
prevRound, proposedBlock, Optional.empty()),
proposerMessageFactory.createProposal(prevRound, proposedBlock, empty()),
Lists.newArrayList(
validatorMessageFactory.createPrepare(
prevRound, proposedBlock.getHash()))))));
Expand All @@ -130,8 +130,7 @@ public void detectsTheSuppliedBlockIsNotInLatestPrepareCertificate() {

final PreparedRoundArtifacts mismatchedRoundArtefacts =
new PreparedRoundArtifacts(
proposerMessageFactory.createProposal(
preparedRound, prevProposedBlock, Optional.empty()),
proposerMessageFactory.createProposal(preparedRound, prevProposedBlock, empty()),
singletonList(
validatorMessageFactory.createPrepare(preparedRound, prevProposedBlock.getHash())));

Expand All @@ -154,7 +153,7 @@ public void correctlyMatchesBlockAgainstLatestInRoundChangeCertificate() {
TestHelpers.createFrom(roundIdentifier, 0, -1);
final Block latterBlock = TestHelpers.createProposalBlock(validators, latterPrepareRound);
final Proposal latterProposal =
proposerMessageFactory.createProposal(latterPrepareRound, latterBlock, Optional.empty());
proposerMessageFactory.createProposal(latterPrepareRound, latterBlock, empty());
final Optional<PreparedRoundArtifacts> latterTerminatedRoundArtefacts =
Optional.of(
new PreparedRoundArtifacts(
Expand All @@ -171,7 +170,7 @@ public void correctlyMatchesBlockAgainstLatestInRoundChangeCertificate() {
final Block earlierBlock =
TestHelpers.createProposalBlock(validators.subList(0, 1), earlierPreparedRound);
final Proposal earlierProposal =
proposerMessageFactory.createProposal(earlierPreparedRound, earlierBlock, Optional.empty());
proposerMessageFactory.createProposal(earlierPreparedRound, earlierBlock, empty());
final Optional<PreparedRoundArtifacts> earlierTerminatedRoundArtefacts =
Optional.of(
new PreparedRoundArtifacts(
Expand Down Expand Up @@ -200,4 +199,23 @@ public void correctlyMatchesBlockAgainstLatestInRoundChangeCertificate() {
roundChangeCert, latterBlock))
.isTrue();
}

@Test
public void roundChangeCertificateWithTwoRoundChangesFromTheSameAuthorFailsValidation() {

final RoundChangeCertificate roundChangeCert =
new RoundChangeCertificate(
org.assertj.core.util.Lists.newArrayList(
proposerMessageFactory
.createRoundChange(roundIdentifier, empty())
.getSignedPayload(),
proposerMessageFactory
.createRoundChange(roundIdentifier, empty())
.getSignedPayload()));

assertThat(
validator.validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot(
roundIdentifier, roundChangeCert))
.isFalse();
}
}