private BlockHashLookup createBlockHashLookup(
      final BlockOverrides blockOverrides,
      final ProtocolSpec newProtocolSpec,
      final BlockHeader blockHeader,
      final Map<Long, Hash> blockHashCache) {
    var blockCallBlockHashLookup =
        blockOverrides
            .getBlockHashLookup()
            .<BlockHashLookup>map(
                blockHashLookup -> (___, blockNumber) -> blockHashLookup.apply(blockNumber))
            .orElseGet(
                () ->
                    newProtocolSpec
                        .getBlockHashProcessor()
                        .createBlockHashLookup(blockchain, blockHeader));
    return (frame, blockNumber) -> {
      if (blockHashCache.containsKey(blockNumber)) {
        return blockHashCache.get(blockNumber);
      }
      return blockCallBlockHashLookup.apply(frame, blockNumber);
    };
  }
Creates a BlockHashLookup for the block simulation. If a BlockHashLookup is provided in the
BlockOverrides, it is used. Otherwise, the default BlockHashLookup is created.

@param blockOverrides The BlockOverrides to use.
@param newProtocolSpec The ProtocolSpec for the block.
@param blockHeader The block header for the simulation.
@param blockHashCache A cache of block hashes.
@return The BlockHashLookup for the block simulation.
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java