@Override
  public BlockProcessingResult processBlock(
      final ProtocolContext protocolContext,
      final Blockchain blockchain,
      final MutableWorldState worldState,
      final Block block,
      final PreprocessingFunction preprocessingBlockFunction) {
    final List<TransactionReceipt> receipts = new ArrayList<>();
    long currentGasUsed = 0;
    long currentBlobGasUsed = 0;

    var blockHeader = block.getHeader();
    var blockBody = block.getBody();
    var ommers = blockBody.getOmmers();
    var transactions = blockBody.getTransactions();
    var maybeWithdrawals = blockBody.getWithdrawals();

    final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(blockHeader);
    final BlockHashLookup blockHashLookup =
        protocolSpec.getBlockHashProcessor().createBlockHashLookup(blockchain, blockHeader);

    final BlockAwareOperationTracer blockTracer =
        getBlockImportTracer(protocolContext, blockHeader);

    final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);

    LOG.trace("traceStartBlock for {}", blockHeader.getNumber());
    blockTracer.traceStartBlock(blockHeader, miningBeneficiary);

    final BlockProcessingContext blockProcessingContext =
        new BlockProcessingContext(
            blockHeader, worldState, protocolSpec, blockHashLookup, blockTracer);
    protocolSpec.getBlockHashProcessor().process(blockProcessingContext);

    Optional<BlockHeader> maybeParentHeader =
        blockchain.getBlockHeader(blockHeader.getParentHash());

    Wei blobGasPrice =
        maybeParentHeader
            .map(
                parentHeader ->
                    protocolSpec
                        .getFeeMarket()
                        .blobGasPricePerGas(
                            calculateExcessBlobGasForParent(protocolSpec, parentHeader)))
            .orElse(Wei.ZERO);

    final Optional<PreprocessingContext> preProcessingContext =
        preprocessingBlockFunction.run(
            protocolContext,
            blockHeader,
            transactions,
            miningBeneficiary,
            blockHashLookup,
            blobGasPrice);

    boolean parallelizedTxFound = false;
    int nbParallelTx = 0;
    for (int i = 0; i < transactions.size(); i++) {
      final Transaction transaction = transactions.get(i);
      if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) {
        return new BlockProcessingResult(Optional.empty(), "provided gas insufficient");
      }
      final WorldUpdater blockUpdater = worldState.updater();

      TransactionProcessingResult transactionProcessingResult =
          getTransactionProcessingResult(
              preProcessingContext,
              blockProcessingContext,
              blockUpdater,
              blobGasPrice,
              miningBeneficiary,
              transaction,
              i,
              blockHashLookup);
      if (transactionProcessingResult.isInvalid()) {
        String errorMessage =
            MessageFormat.format(
                "Block processing error: transaction invalid {0}. Block {1} Transaction {2}",
                transactionProcessingResult.getValidationResult().getErrorMessage(),
                blockHeader.getHash().toHexString(),
                transaction.getHash().toHexString());
        LOG.info(errorMessage);
        if (worldState instanceof BonsaiWorldState) {
          ((BonsaiWorldStateUpdateAccumulator) blockUpdater).reset();
        }
        return new BlockProcessingResult(Optional.empty(), errorMessage);
      }

      blockUpdater.commit();
      blockUpdater.markTransactionBoundary();

      currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining();
      if (transaction.getVersionedHashes().isPresent()) {
        currentBlobGasUsed +=
            (transaction.getVersionedHashes().get().size()
                * protocolSpec.getGasCalculator().getBlobGasPerBlob());
      }

      final TransactionReceipt transactionReceipt =
          transactionReceiptFactory.create(
              transaction.getType(), transactionProcessingResult, worldState, currentGasUsed);
      receipts.add(transactionReceipt);
      if (!parallelizedTxFound
          && transactionProcessingResult.getIsProcessedInParallel().isPresent()) {
        parallelizedTxFound = true;
        nbParallelTx = 1;
      } else if (transactionProcessingResult.getIsProcessedInParallel().isPresent()) {
        nbParallelTx++;
      }
    }
    if (blockHeader.getBlobGasUsed().isPresent()
        && currentBlobGasUsed != blockHeader.getBlobGasUsed().get()) {
      String errorMessage =
          String.format(
              "block did not consume expected blob gas: header %d, transactions %d",
              blockHeader.getBlobGasUsed().get(), currentBlobGasUsed);
      LOG.error(errorMessage);
      return new BlockProcessingResult(Optional.empty(), errorMessage);
    }
    final Optional<WithdrawalsProcessor> maybeWithdrawalsProcessor =
        protocolSpec.getWithdrawalsProcessor();
    if (maybeWithdrawalsProcessor.isPresent() && maybeWithdrawals.isPresent()) {
      try {
        maybeWithdrawalsProcessor
            .get()
            .processWithdrawals(maybeWithdrawals.get(), worldState.updater());
      } catch (final Exception e) {
        LOG.error("failed processing withdrawals", e);
        return new BlockProcessingResult(Optional.empty(), e);
      }
    }

    Optional<List<Request>> maybeRequests = Optional.empty();
    try {
      // EIP-7685: process EL requests
      final Optional<RequestProcessorCoordinator> requestProcessor =
          protocolSpec.getRequestProcessorCoordinator();
      if (requestProcessor.isPresent()) {
        RequestProcessingContext requestProcessingContext =
            new RequestProcessingContext(blockProcessingContext, receipts);
        maybeRequests = Optional.of(requestProcessor.get().process(requestProcessingContext));
      }
    } catch (final Exception e) {
      LOG.error("failed processing requests", e);
      return new BlockProcessingResult(Optional.empty(), e);
    }

    if (maybeRequests.isPresent() && blockHeader.getRequestsHash().isPresent()) {
      Hash calculatedRequestHash = BodyValidation.requestsHash(maybeRequests.get());
      Hash headerRequestsHash = blockHeader.getRequestsHash().get();
      if (!calculatedRequestHash.equals(headerRequestsHash)) {
        return new BlockProcessingResult(
            Optional.empty(),
            "Requests hash mismatch, calculated: "
                + calculatedRequestHash.toHexString()
                + " header: "
                + headerRequestsHash.toHexString());
      }
    }

    if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) {
      // no need to log, rewardCoinbase logs the error.
      if (worldState instanceof BonsaiWorldState) {
        ((BonsaiWorldStateUpdateAccumulator) worldState.updater()).reset();
      }
      return new BlockProcessingResult(Optional.empty(), "ommer too old");
    }

    LOG.trace("traceEndBlock for {}", blockHeader.getNumber());
    blockTracer.traceEndBlock(blockHeader, blockBody);

    try {
      worldState.persist(blockHeader);
    } catch (MerkleTrieException e) {
      LOG.trace("Merkle trie exception during Transaction processing ", e);
      if (worldState instanceof BonsaiWorldState) {
        ((BonsaiWorldStateUpdateAccumulator) worldState.updater()).reset();
      }
      throw e;
    } catch (StateRootMismatchException ex) {
      LOG.error(
          "failed persisting block due to stateroot mismatch; expected {}, actual {}",
          ex.getExpectedRoot().toHexString(),
          ex.getActualRoot().toHexString());
      return new BlockProcessingResult(Optional.empty(), ex.getMessage());
    } catch (Exception e) {
      LOG.error("failed persisting block", e);
      return new BlockProcessingResult(Optional.empty(), e);
    }

    return new BlockProcessingResult(
        Optional.of(new BlockProcessingOutputs(worldState, receipts, maybeRequests)),
        parallelizedTxFound ? Optional.of(nbParallelTx) : Optional.empty());
  }
Processes the block with no privateMetadata and no preprocessor.

@param protocolContext the current context of the protocol
@param blockchain the blockchain to append the block to
@param worldState the world state to apply changes to
@param block the block to process
@return the block processing result
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java