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 }