### Question:
RoundChangeCertificateValidator { public boolean validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot( final ConsensusRoundIdentifier expectedRound, final RoundChangeCertificate roundChangeCert) { 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; } if (!roundChangeCert.getRoundChangePayloads().stream() .allMatch(p -> p.getPayload().getRoundIdentifier().equals(expectedRound))) { LOG.info( "Invalid RoundChangeCertificate, not all embedded RoundChange messages have a " + "matching target round."); return false; } final RoundChangePayloadValidator roundChangeValidator = new RoundChangePayloadValidator( messageValidatorFactory, validators, IbftHelpers.prepareMessageCountForQuorum(quorum), chainHeight); if (!roundChangeCert.getRoundChangePayloads().stream() .allMatch(roundChangeValidator::validateRoundChange)) { LOG.info("Invalid RoundChangeCertificate, embedded RoundChange message failed validation."); return false; } return true; } RoundChangeCertificateValidator(
      final Collection<Address> validators,
      final MessageValidatorForHeightFactory messageValidatorFactory,
      final long chainHeight); boolean validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot(
      final ConsensusRoundIdentifier expectedRound, final RoundChangeCertificate roundChangeCert); boolean validateProposalMessageMatchesLatestPrepareCertificate(
      final RoundChangeCertificate roundChangeCert, final Block proposedBlock);  }### Answer:
@Test public void proposalWithEmptyRoundChangeCertificateFails() { final RoundChangeCertificate cert = new RoundChangeCertificate(Collections.emptyList()); assertThat( validator.validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot( roundIdentifier, cert)) .isFalse(); }
@Test public void roundChangeMessagesDoNotAllTargetRoundFails() { final ConsensusRoundIdentifier prevRound = TestHelpers.createFrom(roundIdentifier, 0, -1); final RoundChangeCertificate.Builder roundChangeBuilder = new RoundChangeCertificate.Builder(); roundChangeBuilder.appendRoundChangeMessage( proposerMessageFactory.createRoundChange(roundIdentifier, empty())); roundChangeBuilder.appendRoundChangeMessage( proposerMessageFactory.createRoundChange(prevRound, empty())); assertThat( validator.validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot( roundIdentifier, roundChangeBuilder.buildCertificate())) .isFalse(); }
@Test public void invalidPrepareMessageInOnePrepareCertificateFails() { final ConsensusRoundIdentifier prevRound = TestHelpers.createFrom(roundIdentifier, 0, -1); final RoundChangeCertificate.Builder roundChangeBuilder = new RoundChangeCertificate.Builder(); roundChangeBuilder.appendRoundChangeMessage( proposerMessageFactory.createRoundChange( roundIdentifier, Optional.of( new PreparedRoundArtifacts( proposerMessageFactory.createProposal(prevRound, proposedBlock, empty()), Lists.newArrayList( validatorMessageFactory.createPrepare( prevRound, proposedBlock.getHash())))))); when(signedDataValidator.validatePrepare(any())).thenReturn(false); assertThat( validator.validateRoundChangeMessagesAndEnsureTargetRoundMatchesRoot( roundIdentifier, roundChangeBuilder.buildCertificate())) .isFalse(); }
@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(); }