@Override
  public BlockProcessingResult validateAndProcessBlock(
      final ProtocolContext context,
      final Block block,
      final HeaderValidationMode headerValidationMode,
      final HeaderValidationMode ommerValidationMode,
      final boolean shouldUpdateHead,
      final boolean shouldRecordBadBlock) {

    final BlockHeader header = block.getHeader();
    final BlockHeader parentHeader;

    try {
      final MutableBlockchain blockchain = context.getBlockchain();
      final Optional<BlockHeader> maybeParentHeader =
          blockchain.getBlockHeader(header.getParentHash());
      if (maybeParentHeader.isEmpty()) {
        var retval =
            new BlockProcessingResult(
                "Parent block with hash " + header.getParentHash() + " not present");
        // Blocks should not be marked bad due to missing data
        handleFailedBlockProcessing(block, retval, false, context);
        return retval;
      }
      parentHeader = maybeParentHeader.get();

      if (!blockHeaderValidator.validateHeader(
          header, parentHeader, context, headerValidationMode)) {
        final String error = String.format("Header validation failed (%s)", headerValidationMode);
        var retval = new BlockProcessingResult(error);
        handleFailedBlockProcessing(block, retval, shouldRecordBadBlock, context);
        return retval;
      }
    } catch (StorageException ex) {
      var retval = new BlockProcessingResult(Optional.empty(), ex);
      // Blocks should not be marked bad due to a local storage failure
      handleFailedBlockProcessing(block, retval, false, context);
      return retval;
    }

    final WorldStateQueryParams worldStateQueryParams =
        WorldStateQueryParams.newBuilder()
            .withBlockHeader(parentHeader)
            .withShouldWorldStateUpdateHead(shouldUpdateHead)
            .build();
    try (final var worldState =
        context.getWorldStateArchive().getWorldState(worldStateQueryParams).orElse(null)) {

      if (worldState == null) {
        var retval =
            new BlockProcessingResult(
                "Unable to process block because parent world state "
                    + parentHeader.getStateRoot()
                    + " is not available");
        // Blocks should not be marked bad due to missing data
        handleFailedBlockProcessing(block, retval, false, context);
        return retval;
      }
      var result = processBlock(context, worldState, block);
      if (result.isFailed()) {
        handleFailedBlockProcessing(block, result, shouldRecordBadBlock, context);
        return result;
      } else {
        List<TransactionReceipt> receipts =
            result.getYield().map(BlockProcessingOutputs::getReceipts).orElse(new ArrayList<>());
        Optional<List<Request>> maybeRequests =
            result.getYield().flatMap(BlockProcessingOutputs::getRequests);
        if (!blockBodyValidator.validateBody(
            context,
            block,
            receipts,
            worldState.rootHash(),
            ommerValidationMode,
            BodyValidationMode.FULL)) {
          result = new BlockProcessingResult("failed to validate output of imported block");
          handleFailedBlockProcessing(block, result, shouldRecordBadBlock, context);
          return result;
        }

        return new BlockProcessingResult(
            Optional.of(new BlockProcessingOutputs(worldState, receipts, maybeRequests)),
            result.getNbParallelizedTransactions());
      }
    } catch (MerkleTrieException ex) {
      context.getWorldStateArchive().heal(ex.getMaybeAddress(), ex.getLocation());
      return new BlockProcessingResult(Optional.empty(), ex);
    } catch (StorageException ex) {
      var retval = new BlockProcessingResult(Optional.empty(), ex);
      // Do not record bad block due to a local storage issue
      handleFailedBlockProcessing(block, retval, false, context);
      return retval;
    } catch (Exception ex) {
      // Wrap checked autocloseable exception from try-with-resources
      throw new RuntimeException(ex);
    }
  }
Performs a full validation and processing of a block

@param context the {@link ProtocolContext}
@param block the block being validated and processed
@param headerValidationMode the {@link HeaderValidationMode} used for validating the header
@param ommerValidationMode the {@link HeaderValidationMode} used for validating the ommers
@return an optional containing the {@link BlockProcessingOutputs} with the output of processing
    the block, empty if the block was deemed invalid or couldn't be processed
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java