Coverage Summary for Class: DifficultyCalculator (co.rsk.core)

Class Class, % Method, % Line, %
DifficultyCalculator 100% (1/1) 100% (4/4) 82.4% (28/34)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2017 RSK Labs Ltd. 4  * 5  * This program is free software: you can redistribute it and/or modify 6  * it under the terms of the GNU Lesser General Public License as published by 7  * the Free Software Foundation, either version 3 of the License, or 8  * (at your option) any later version. 9  * 10  * This program is distributed in the hope that it will be useful, 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13  * GNU Lesser General Public License for more details. 14  * 15  * You should have received a copy of the GNU Lesser General Public License 16  * along with this program. If not, see <http://www.gnu.org/licenses/>. 17  */ 18  19 package co.rsk.core; 20  21 import org.ethereum.config.Constants; 22 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 23 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 24 import org.ethereum.core.BlockHeader; 25  26 import java.math.BigInteger; 27  28 import static org.ethereum.util.BIUtil.max; 29  30 public class DifficultyCalculator { 31  private final ActivationConfig activationConfig; 32  private final Constants constants; 33  34  public DifficultyCalculator(ActivationConfig activationConfig, Constants constants) { 35  this.activationConfig = activationConfig; 36  this.constants = constants; 37  } 38  39  public BlockDifficulty calcDifficulty(BlockHeader header, BlockHeader parentHeader) { 40  boolean rskip97Active = activationConfig.isActive(ConsensusRule.RSKIP97, header.getNumber()); 41  if (!rskip97Active) { 42  // If more than 10 minutes, reset to minimum difficulty to allow private mining 43  if (header.getTimestamp() >= parentHeader.getTimestamp() + 600) { 44  return constants.getMinimumDifficulty(); 45  } 46  } 47  48  return getBlockDifficulty(header, parentHeader); 49  } 50  51  private BlockDifficulty getBlockDifficulty( 52  BlockHeader curBlockHeader, 53  BlockHeader parent) { 54  BlockDifficulty pd = parent.getDifficulty(); 55  long parentBlockTS = parent.getTimestamp(); 56  int uncleCount = curBlockHeader.getUncleCount(); 57  long curBlockTS = curBlockHeader.getTimestamp(); 58  int duration = constants.getDurationLimit(); 59  BigInteger difDivisor = constants.getDifficultyBoundDivisor(activationConfig.forBlock(curBlockHeader.getNumber())); 60  BlockDifficulty minDif = constants.getMinimumDifficulty(); 61  return calcDifficultyWithTimeStamps(curBlockTS, parentBlockTS, pd, uncleCount, duration, difDivisor, minDif); 62  } 63  64  private static BlockDifficulty calcDifficultyWithTimeStamps( 65  long curBlockTS, 66  long parentBlockTS, 67  BlockDifficulty pd, 68  int uncleCount, 69  int duration, 70  BigInteger difDivisor, 71  BlockDifficulty minDif) { 72  long delta = curBlockTS - parentBlockTS; 73  if (delta < 0) { 74  return pd; 75  } 76  77  int calcDur = (1 + uncleCount) * duration; 78  int sign = 0; 79  if (calcDur > delta) { 80  sign = 1; 81  } else if (calcDur < delta) { 82  sign = -1; 83  } 84  85  if (sign == 0) { 86  return pd; 87  } 88  89  BigInteger pdValue = pd.asBigInteger(); 90  BigInteger quotient = pdValue.divide(difDivisor); 91  92  BigInteger fromParent; 93  if (sign == 1) { 94  fromParent = pdValue.add(quotient); 95  } else { 96  fromParent = pdValue.subtract(quotient); 97  } 98  99  // If parent difficulty is zero (maybe a genesis block), 100  // then the first child difficulty MUST 101  // be greater or equal getMinimumDifficulty(). That's why the max() is applied in both the add and the sub 102  // cases. 103  // Note that we have to apply max() first in case fromParent ended up being negative. 104  return new BlockDifficulty(max(minDif.asBigInteger(), fromParent)); 105  } 106 }