private static void darkGravityWave3Check(
      StoredBlock prevBlock, Block added, BlockStore store, NetworkParameters params) {
    StoredBlock blockReading = prevBlock;

    long actualTimespan = 0;
    long lastBlockTime = 0;
    long pastBlocksMin = 24;
    long pastBlocksMax = 24;
    long countBlocks = 0;

    BigInteger pastDifficultyAverage = BigInteger.ZERO;
    BigInteger pastDifficultyAveragePrev = BigInteger.ZERO;

    if (prevBlock == null || prevBlock.getHeight() == 0 || prevBlock.getHeight() < pastBlocksMin) {
      verifyDifficulty(prevBlock, added, params.getMaxTarget(), params);
      return;
    }

    for (int i = 1; blockReading.getHeight() > 0; i++) {
      if (i > pastBlocksMax) {
        break;
      }
      countBlocks++;

      if (countBlocks <= pastBlocksMin) {
        if (countBlocks == 1) {
          pastDifficultyAverage = blockReading.getHeader().getDifficultyTargetAsInteger();
        } else {
          pastDifficultyAverage =
              pastDifficultyAveragePrev
                  .multiply(BigInteger.valueOf(countBlocks))
                  .add(blockReading.getHeader().getDifficultyTargetAsInteger())
                  .divide(BigInteger.valueOf(countBlocks + 1));
        }
        pastDifficultyAveragePrev = pastDifficultyAverage;
      }

      if (lastBlockTime > 0) {
        actualTimespan += (lastBlockTime - blockReading.getHeader().getTimeSeconds());
      }
      lastBlockTime = blockReading.getHeader().getTimeSeconds();

      try {
        blockReading = store.get(blockReading.getHeader().getPrevBlockHash());
        if (blockReading == null) {
          return;
        }
      } catch (BlockStoreException ex) {
        log.warn("Dark gravity wave 3 descended to start of the chain");
        return;
      }
    }

    BigInteger bnNew = pastDifficultyAverage;

    long targetTimespan =
        countBlocks * params.getTargetSpacing(prevBlock.getHeader(), prevBlock.getHeight());

    if (actualTimespan < targetTimespan / 3) {
      actualTimespan = targetTimespan / 3;
    }
    if (actualTimespan > targetTimespan * 3) {
      actualTimespan = targetTimespan * 3;
    }

    // Retarget
    bnNew = bnNew.multiply(BigInteger.valueOf(actualTimespan));
    bnNew = bnNew.divide(BigInteger.valueOf(targetTimespan));

    verifyDifficulty(prevBlock, added, bnNew, params);
  }
  private static void darkGravityWaveCheck(
      StoredBlock prevBlock, Block added, BlockStore store, NetworkParameters params) {
    StoredBlock blockReading = prevBlock;

    long blockTimeAverage = 0;
    long blockTimeAveragePrev = 0;
    long blockTimeCount = 0;
    long blockTimeSum2 = 0;
    long blockTimeCount2 = 0;
    long lastBlockTime = 0;
    long pastBlocksMin = 14;
    long pastBlocksMax = 140;
    long countBlocks = 0;

    BigInteger pastDifficultyAverage = BigInteger.valueOf(0);
    BigInteger pastDifficultyAveragePrev = BigInteger.valueOf(0);

    if (prevBlock == null || prevBlock.getHeight() == 0 || prevBlock.getHeight() < pastBlocksMin) {
      verifyDifficulty(prevBlock, added, params.getMaxTarget(), params);
      return;
    }

    for (int i = 1; blockReading.getHeight() > 0; i++) {
      if (i > pastBlocksMax) {
        break;
      }
      countBlocks++;

      if (countBlocks <= pastBlocksMin) {
        if (countBlocks == 1) {
          pastDifficultyAverage = blockReading.getHeader().getDifficultyTargetAsInteger();
        } else {
          pastDifficultyAverage =
              blockReading
                  .getHeader()
                  .getDifficultyTargetAsInteger()
                  .subtract(pastDifficultyAveragePrev)
                  .divide(BigInteger.valueOf(countBlocks))
                  .add(pastDifficultyAveragePrev);
        }
        pastDifficultyAveragePrev = pastDifficultyAverage;
      }

      if (lastBlockTime > 0) {
        long diff = lastBlockTime - blockReading.getHeader().getTimeSeconds();
        if (blockTimeCount <= pastBlocksMin) {
          blockTimeCount++;

          if (blockTimeCount == 1) {
            blockTimeAverage = diff;
          } else {
            blockTimeAverage =
                (diff - blockTimeAveragePrev) / blockTimeCount + blockTimeAveragePrev;
          }
          blockTimeAveragePrev = blockTimeAverage;
        }
        blockTimeCount2++;
        blockTimeSum2 += diff;
      }
      lastBlockTime = blockReading.getHeader().getTimeSeconds();

      try {
        blockReading = store.get(blockReading.getHeader().getPrevBlockHash());
        if (blockReading == null) {
          return;
        }
      } catch (BlockStoreException ex) {
        log.warn("Dark gravity wave 3 descended to start of the chain");
        return;
      }
    }

    BigInteger bnNew = pastDifficultyAverage;

    if (blockTimeCount != 0 && blockTimeCount2 != 0) {
      double smartAverage =
          ((double) blockTimeAverage) * 0.7
              + ((double) blockTimeSum2 / (double) blockTimeCount2) * 0.3;
      if (smartAverage < 1) smartAverage = 1;

      final int targetSpacing =
          params.getTargetSpacing(prevBlock.getHeader(), prevBlock.getHeight());
      final double shift = targetSpacing / smartAverage;

      final double dCountBlocks = (double) countBlocks;
      double actualTimespan = dCountBlocks * ((double) targetSpacing) / shift;
      double targetTimespan = dCountBlocks * targetSpacing;

      if (actualTimespan < targetTimespan / 3) actualTimespan = targetTimespan / 3;
      if (actualTimespan > targetTimespan * 3) actualTimespan = targetTimespan * 3;

      // Retarget
      bnNew = bnNew.multiply(BigInteger.valueOf((long) actualTimespan));
      bnNew = bnNew.divide(BigInteger.valueOf((long) targetTimespan));
    }

    verifyDifficulty(prevBlock, added, bnNew, params);
  }