private void checkForBitFlip(DeterministicKey k) {
   DeterministicKey parent = checkNotNull(k.getParent());
   byte[] rederived =
       HDKeyDerivation.deriveChildKeyBytesFromPublic(
               parent, k.getChildNumber(), HDKeyDerivation.PublicDeriveMode.WITH_INVERSION)
           .keyBytes;
   byte[] actual = k.getPubKey();
   if (!Arrays.equals(rederived, actual))
     throw new IllegalStateException(
         String.format(
             "Bit-flip check failed: %s vs %s",
             Arrays.toString(rederived), Arrays.toString(actual)));
 }
  /** Gets the median timestamp of the last 11 blocks */
  private static long getMedianTimestampOfRecentBlocks(StoredBlock storedBlock, BlockStore store)
      throws BlockStoreException {
    long[] timestamps = new long[11];
    int unused = 9;
    timestamps[10] = storedBlock.getHeader().getTimeSeconds();
    while (unused >= 0 && (storedBlock = storedBlock.getPrev(store)) != null)
      timestamps[unused--] = storedBlock.getHeader().getTimeSeconds();

    Arrays.sort(timestamps, unused + 1, 11);
    return timestamps[unused + (11 - unused) / 2];
  }
  @Override
  @Nullable
  public StoredBlock get(Sha256Hash hash) throws BlockStoreException {
    final MappedByteBuffer buffer = this.buffer;
    if (buffer == null) throw new BlockStoreException("Store closed");

    lock.lock();
    try {
      StoredBlock cacheHit = blockCache.get(hash);
      if (cacheHit != null) return cacheHit;
      if (notFoundCache.get(hash) != null) return null;

      // Starting from the current tip of the ring work backwards until we have either found the
      // block or
      // wrapped around.
      int cursor = getRingCursor(buffer);
      final int startingPoint = cursor;
      final int fileSize = getFileSize();
      final byte[] targetHashBytes = hash.getBytes();
      byte[] scratch = new byte[32];
      do {
        cursor -= RECORD_SIZE;
        if (cursor < FILE_PROLOGUE_BYTES) {
          // We hit the start, so wrap around.
          cursor = fileSize - RECORD_SIZE;
        }
        // Cursor is now at the start of the next record to check, so read the hash and compare it.
        buffer.position(cursor);
        buffer.get(scratch);
        if (Arrays.equals(scratch, targetHashBytes)) {
          // Found the target.
          StoredBlock storedBlock = StoredBlock.deserializeCompact(params, buffer);
          blockCache.put(hash, storedBlock);
          return storedBlock;
        }
      } while (cursor != startingPoint);
      // Not found.
      notFoundCache.put(hash, notFoundMarker);
      return null;
    } catch (ProtocolException e) {
      throw new RuntimeException(e); // Cannot happen.
    } finally {
      lock.unlock();
    }
  }