private static QbftConfigOptions createQbftConfigOptions(
      final ForkSpec<QbftConfigOptions> lastSpec, final QbftFork fork) {
    final MutableQbftConfigOptions bftConfigOptions =
        new MutableQbftConfigOptions(lastSpec.getValue());

    fork.getBlockPeriodSeconds().ifPresent(bftConfigOptions::setBlockPeriodSeconds);
    fork.getEmptyBlockPeriodSeconds().ifPresent(bftConfigOptions::setEmptyBlockPeriodSeconds);
    fork.getBlockPeriodMilliseconds().ifPresent(bftConfigOptions::setBlockPeriodMilliseconds);
    fork.getBlockRewardWei().ifPresent(bftConfigOptions::setBlockRewardWei);

    if (fork.isMiningBeneficiaryConfigured()) {
      // Only override if mining beneficiary is explicitly configured
      bftConfigOptions.setMiningBeneficiary(fork.getMiningBeneficiary());
    }

    if (fork.getValidatorSelectionMode().isPresent()) {
      final VALIDATOR_SELECTION_MODE mode = fork.getValidatorSelectionMode().get();
      if (mode == VALIDATOR_SELECTION_MODE.BLOCKHEADER) {
        final Optional<List<String>> optionalValidators = fork.getValidators();
        if (optionalValidators.isEmpty() || optionalValidators.get().isEmpty()) {
          throw new IllegalStateException(
              "QBFT transition to blockheader mode requires a validators list containing at least one validator");
        }
        bftConfigOptions.setValidatorContractAddress(Optional.empty());
      } else if (mode == VALIDATOR_SELECTION_MODE.CONTRACT
          && fork.getValidatorContractAddress().isPresent()) {
        bftConfigOptions.setValidatorContractAddress(fork.getValidatorContractAddress());
      } else if (fork.getValidatorContractAddress().isEmpty()) {
        throw new IllegalStateException(
            "QBFT transition has config with contract mode but no contract address");
      }
    }

    return bftConfigOptions;
  }
Create forks schedule.

@param genesisConfig the genesis config
@return the forks schedule
consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftForksSchedulesFactory.java