private static ProtocolSpecBuilder applyCliqueSpecificModifications(
      final EpochManager epochManager,
      final long secondsBetweenBlocks,
      final boolean createEmptyBlocks,
      final Address localNodeAddress,
      final ProtocolSpecBuilder specBuilder) {

    return specBuilder
        .blockHeaderValidatorBuilder(
            (baseFeeMarket, gasCalculator, gasLimitCalculator) ->
                getBlockHeaderValidator(
                    epochManager, secondsBetweenBlocks, createEmptyBlocks, baseFeeMarket))
        .ommerHeaderValidatorBuilder(
            (baseFeeMarket, gasCalculator, gasLimitCalculator) ->
                getBlockHeaderValidator(
                    epochManager, secondsBetweenBlocks, createEmptyBlocks, baseFeeMarket))
        .blockBodyValidatorBuilder(MainnetBlockBodyValidator::new)
        .blockValidatorBuilder(MainnetProtocolSpecs.blockValidatorBuilder())
        .blockImporterBuilder(MainnetBlockImporter::new)
        .difficultyCalculator(new CliqueDifficultyCalculator(localNodeAddress))
        .blockReward(Wei.ZERO)
        .skipZeroBlockRewards(true)
        .miningBeneficiaryCalculator(CliqueHelpers::getProposerOfBlock)
        .blockHeaderFunctions(new CliqueBlockHeaderFunctions());
  }
Create protocol schedule.

@param config the config
@param forksSchedule the transitions
@param nodeKey the node key
@param isRevertReasonEnabled the is revert reason enabled
@param evmConfiguration the evm configuration
@param miningConfiguration the mining configuration
@param badBlockManager the cache to use to keep invalid blocks
@param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled
@param metricsSystem A metricSystem instance to be able to expose metrics in the underlying
    calls
@return the protocol schedule
consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java