private void buildBlockAndMaybePropose(
      final ConsensusRoundIdentifier roundIdentifier, final QbftRound qbftRound) {

    // mining will be checked against round 0 as the current round is initialised to 0 above
    final boolean isProposer =
        finalState.isLocalNodeProposerForRound(qbftRound.getRoundIdentifier());

    if (!isProposer) {
      // nothing to do here...
      LOG.trace("This node is not a proposer so it will not send a proposal: " + roundIdentifier);
      return;
    }

    final long headerTimeStampSeconds = Math.round(clock.millis() / 1000D);
    final QbftBlock block = qbftRound.createBlock(headerTimeStampSeconds);
    if (!block.isEmpty()) {
      LOG.trace(
          "Block is not empty and this node is a proposer so it will send a proposal: "
              + roundIdentifier);
      qbftRound.updateStateWithProposalAndTransmit(block);
    } else {
      // handle the block times period
      final long currentTimeInMillis = finalState.getClock().millis();
      boolean emptyBlockExpired =
          finalState
              .getBlockTimer()
              .checkEmptyBlockExpired(parentHeader::getTimestamp, currentTimeInMillis);
      if (emptyBlockExpired) {
        LOG.trace(
            "Block has no transactions and this node is a proposer so it will send a proposal: "
                + roundIdentifier);
        qbftRound.updateStateWithProposalAndTransmit(block);
      } else {
        LOG.trace(
            "Block has no transactions but emptyBlockPeriodSeconds did not expired yet: "
                + roundIdentifier);
        finalState
            .getBlockTimer()
            .resetTimerForEmptyBlock(
                roundIdentifier, parentHeader::getTimestamp, currentTimeInMillis);
        finalState.getRoundTimer().cancelTimer();
        currentRound = Optional.empty();
      }
    }
  }
Instantiates a new Qbft block height manager. Secondary constructor with early round change
option.

@param parentHeader the parent header
@param finalState the final state
@param roundChangeManager the round change manager
@param qbftRoundFactory the qbft round factory
@param clock the clock
@param messageValidatorFactory the message validator factory
@param messageFactory the message factory
@param validatorProvider the validator provider
@param isEarlyRoundChangeEnabled enable round change when f+1 RC messages are received
consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java