github.com/aquanetwork/aquachain@v1.7.8/consensus/aquahash/difficulty.go (about)

     1  package aquahash
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"gitlab.com/aquachain/aquachain/common/math"
     7  	"gitlab.com/aquachain/aquachain/core/types"
     8  	"gitlab.com/aquachain/aquachain/params"
     9  )
    10  
    11  // Some weird constants to avoid constant memory allocs for them.
    12  var (
    13  	expDiffPeriod = big.NewInt(100000)
    14  	big1          = big.NewInt(1)
    15  	big2          = big.NewInt(2)
    16  	big10         = big.NewInt(10)
    17  	big240        = big.NewInt(240)
    18  	bigMinus99    = big.NewInt(-99)
    19  	big10000      = big.NewInt(10000)
    20  )
    21  
    22  // calcDifficultyHomestead is the difficulty adjustment algorithm. It returns
    23  // the difficulty that a new block should have when created at time given the
    24  // parent block's time and difficulty. The calculation uses the Homestead rules.
    25  func calcDifficultyHomestead(time uint64, parent *types.Header, chainID uint64) *big.Int {
    26  	// https://github.com/aquanetwork/EIPs/blob/master/EIPS/eip-2.md
    27  	// algorithm:
    28  	// diff = (parent_diff +
    29  	//         (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
    30  	//        ) + 2^(periodCount - 2)
    31  	bigTime := new(big.Int).SetUint64(time)
    32  	bigParentTime := new(big.Int).Set(parent.Time)
    33  
    34  	// holds intermediate values to make the algo easier to read & audit
    35  	x := new(big.Int)
    36  	y := new(big.Int)
    37  
    38  	// 1 - (block_timestamp - parent_timestamp) // 10
    39  	x.Sub(bigTime, bigParentTime)
    40  	x.Div(x, big10)
    41  	x.Sub(big1, x)
    42  
    43  	// max(1 - (block_timestamp - parent_timestamp) // 10, -99)
    44  	if x.Cmp(bigMinus99) < 0 {
    45  		x.Set(bigMinus99)
    46  	}
    47  	// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
    48  	y.Div(parent.Difficulty, params.DifficultyBoundDivisor)
    49  	x.Mul(y, x)
    50  	x.Add(parent.Difficulty, x)
    51  
    52  	// testnet no minimum
    53  	if chainID == params.MainnetChainConfig.ChainId.Uint64() {
    54  		x = math.BigMax(x, params.MinimumDifficultyGenesis)
    55  	}
    56  	return x
    57  }
    58  
    59  // calcDifficultyHF1 is the difficulty adjustment algorithm. It returns
    60  // the difficulty that a new block should have when created at time given the
    61  // parent block's time and difficulty. The calculation uses modified Homestead rules.
    62  // It is flawed, target 10 seconds
    63  func calcDifficultyHF1(time uint64, parent *types.Header, chainID uint64) *big.Int {
    64  	bigTime := new(big.Int).SetUint64(time)
    65  	bigParentTime := new(big.Int).Set(parent.Time)
    66  
    67  	// holds intermediate values to make the algo easier to read & audit
    68  	x := new(big.Int)
    69  	y := new(big.Int)
    70  
    71  	// 1 - (block_timestamp - parent_timestamp) // 10
    72  	x.Sub(bigTime, bigParentTime)
    73  	x.Div(x, big10)
    74  	x.Sub(big1, x)
    75  
    76  	// max(1 - (block_timestamp - parent_timestamp) // 10, -99)
    77  	if x.Cmp(bigMinus99) < 0 {
    78  		x.Set(bigMinus99)
    79  	}
    80  	// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
    81  	y.Div(parent.Difficulty, params.DifficultyBoundDivisor)
    82  	x.Mul(y, x)
    83  	x.Add(parent.Difficulty, x)
    84  
    85  	// minimum difficulty can ever be (before exponential factor)
    86  	if chainID == params.MainnetChainConfig.ChainId.Uint64() {
    87  		x = math.BigMax(x, params.MinimumDifficultyHF1)
    88  	}
    89  	return x
    90  }
    91  
    92  // calcDifficultyHFX combines all difficulty algorithms
    93  func calcDifficultyHFX(config *params.ChainConfig, time uint64, parent, grandparent *types.Header) *big.Int {
    94  	var (
    95  		diff          = new(big.Int)
    96  		next          = new(big.Int).Add(parent.Number, big1)
    97  		chainID       = config.ChainId.Uint64()
    98  		hf            = config.UseHF(next)
    99  		adjust        *big.Int
   100  		bigTime       = new(big.Int)
   101  		bigParentTime = new(big.Int)
   102  		limit         = params.DurationLimitHF6 // target 240 seconds
   103  		min           = params.MinimumDifficultyHF5
   104  		mainnet       = params.MainnetChainConfig.ChainId.Uint64() == chainID // bool
   105  	)
   106  	if !mainnet {
   107  		min = params.MinimumDifficultyHF5Testnet
   108  	}
   109  
   110  	if hf > params.KnownHF {
   111  		panic("unknown HF not implemented")
   112  	}
   113  
   114  	switch hf {
   115  	case 9:
   116  		return calcDifficultyGrandparent(time, parent, grandparent, hf, chainID)
   117  	case 8:
   118  		if next.Cmp(config.GetHF(8)) == 0 && mainnet {
   119  			return params.MinimumDifficultyHF5
   120  		}
   121  		if next.Cmp(config.GetHF(8)) == 0 && !mainnet {
   122  			return params.MinimumDifficultyHF8Testnet
   123  		}
   124  		adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisorHF8)
   125  		if !mainnet {
   126  			adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisorHF8Testnet)
   127  			min = params.MinimumDifficultyHF8Testnet
   128  		}
   129  	case 6, 7:
   130  		adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisorHF6)
   131  	case 5:
   132  		if next.Cmp(config.GetHF(5)) == 0 && mainnet {
   133  			return params.MinimumDifficultyHF5
   134  		}
   135  		if next.Cmp(config.GetHF(5)) == 0 && !mainnet {
   136  			return params.MinimumDifficultyHF5Testnet
   137  		}
   138  		limit = params.DurationLimit // not accurate, fixed in hf6
   139  		adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisorHF5)
   140  		if mainnet {
   141  			min = params.MinimumDifficultyHF5
   142  		}
   143  	case 3, 4:
   144  		limit = params.DurationLimit // not accurate, fixed in hf6
   145  		adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor)
   146  		if mainnet {
   147  			min = params.MinimumDifficultyHF3
   148  		}
   149  	case 2:
   150  		limit = params.DurationLimit // not accurate, fixed in hf6
   151  		adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor)
   152  		if mainnet {
   153  			min = params.MinimumDifficultyHF1
   154  		}
   155  	case 1:
   156  		return calcDifficultyHF1(time, parent, chainID)
   157  	case 0:
   158  		return calcDifficultyHomestead(time, parent, chainID)
   159  	default:
   160  		panic("calcDifficulty: invalid hf")
   161  	}
   162  
   163  	bigTime.SetUint64(time)
   164  	bigParentTime.Set(parent.Time)
   165  
   166  	// calculate difficulty
   167  	if bigTime.Sub(bigTime, bigParentTime).Cmp(limit) < 0 {
   168  		diff.Add(parent.Difficulty, adjust)
   169  	} else {
   170  		diff.Sub(parent.Difficulty, adjust)
   171  	}
   172  
   173  	if diff.Cmp(min) < 0 {
   174  		diff.Set(min)
   175  	}
   176  
   177  	return diff
   178  }
   179  
   180  // calcDifficultyGrandparent experimental
   181  func calcDifficultyGrandparent(time uint64, parent, grandparent *types.Header, hf int, chainID uint64) *big.Int {
   182  	bigGrandparentTime := new(big.Int).Set(grandparent.Time)
   183  	bigParentTime := new(big.Int).Set(parent.Time)
   184  	if bigParentTime.Cmp(bigGrandparentTime) <= 0 {
   185  		panic("invalid code")
   186  	}
   187  	// holds intermediate values to make the algo easier to read & audit
   188  	x := new(big.Int)
   189  	y := new(big.Int)
   190  
   191  	divisor := params.DifficultyBoundDivisorHF5
   192  
   193  	// 1 - (block_timestamp - parent_timestamp) // 240
   194  	x.Sub(bigParentTime, bigGrandparentTime)
   195  	x.Div(x, big240)
   196  	x.Sub(big1, x)
   197  
   198  	// max(1 - (block_timestamp - parent_timestamp) // 240, -99)
   199  	if x.Cmp(bigMinus99) < 0 {
   200  		x.Set(bigMinus99)
   201  	}
   202  
   203  	if grandparent.Difficulty.Cmp(big10000) < 0 {
   204  		divisor = params.DifficultyBoundDivisorHF5
   205  	} else {
   206  		divisor = params.DifficultyBoundDivisorHF8
   207  	}
   208  	// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
   209  	y.Div(grandparent.Difficulty, divisor)
   210  	x.Mul(y, x)
   211  	x.Add(grandparent.Difficulty, x)
   212  
   213  	// minimum difficulty can ever be (before exponential factor)
   214  	if chainID == params.MainnetChainConfig.ChainId.Uint64() {
   215  		x = math.BigMax(x, params.MinimumDifficultyHF5)
   216  	} else {
   217  		x = math.BigMax(x, params.MinimumDifficultyHF5Testnet)
   218  	}
   219  	return x
   220  }