private synchronized void doRoundChange(final int newRoundNumber) {

    if (currentRound.isPresent()
        && currentRound.get().getRoundIdentifier().getRoundNumber() >= newRoundNumber) {
      return;
    }
    LOG.debug(
        "Round has expired or changing based on RC quorum, creating PreparedCertificate and notifying peers. round={}",
        currentRound.get().getRoundIdentifier());
    final Optional<PreparedCertificate> preparedCertificate =
        currentRound.get().constructPreparedCertificate();

    if (preparedCertificate.isPresent()) {
      latestPreparedCertificate = preparedCertificate;
    }

    startNewRound(newRoundNumber);
    if (currentRound.isEmpty()) {
      LOG.info("Failed to start round ");
      return;
    }
    QbftRound qbftRoundNew = currentRound.get();

    try {
      final RoundChange localRoundChange =
          messageFactory.createRoundChange(
              qbftRoundNew.getRoundIdentifier(), latestPreparedCertificate);

      // Its possible the locally created RoundChange triggers the transmission of a NewRound
      // message - so it must be handled accordingly.
      handleRoundChangePayload(localRoundChange);
    } catch (final SecurityModuleException e) {
      LOG.warn("Failed to create signed RoundChange message.", e);
    }

    transmitter.multicastRoundChange(qbftRoundNew.getRoundIdentifier(), latestPreparedCertificate);
  }
If the list of validators for the next block to be proposed/imported has changed from the
previous block, log the change. Only log for round 0 (i.e. once per block).

@param qbftRound The current round
consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java