gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/consensus/aquahash/difficulty.go (about) 1 // Copyright 2018 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The aquachain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the aquachain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package aquahash 18 19 import ( 20 "math/big" 21 22 "gitlab.com/aquachain/aquachain/common/math" 23 "gitlab.com/aquachain/aquachain/core/types" 24 "gitlab.com/aquachain/aquachain/params" 25 ) 26 27 // Some weird constants to avoid constant memory allocs for them. 28 var ( 29 expDiffPeriod = big.NewInt(100000) 30 big1 = big.NewInt(1) 31 big2 = big.NewInt(2) 32 big10 = big.NewInt(10) 33 big240 = big.NewInt(240) 34 bigMinus99 = big.NewInt(-99) 35 big10000 = big.NewInt(10000) 36 ) 37 38 // calcDifficultyHomestead is the difficulty adjustment algorithm. It returns 39 // the difficulty that a new block should have when created at time given the 40 // parent block's time and difficulty. The calculation uses the Homestead rules. 41 func calcDifficultyStarting(time uint64, parent *types.Header, chainID uint64) *big.Int { 42 // https://github.com/aquanetwork/EIPs/blob/master/EIPS/eip-2.md 43 // algorithm: 44 // diff = (parent_diff + 45 // (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) 46 // ) + 2^(periodCount - 2) 47 bigTime := new(big.Int).SetUint64(time) 48 bigParentTime := new(big.Int).Set(parent.Time) 49 50 // holds intermediate values to make the algo easier to read & audit 51 x := new(big.Int) 52 y := new(big.Int) 53 54 // 1 - (block_timestamp - parent_timestamp) // 10 55 x.Sub(bigTime, bigParentTime) 56 x.Div(x, big10) 57 x.Sub(big1, x) 58 59 // max(1 - (block_timestamp - parent_timestamp) // 10, -99) 60 if x.Cmp(bigMinus99) < 0 { 61 x.Set(bigMinus99) 62 } 63 // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) 64 y.Div(parent.Difficulty, params.DifficultyBoundDivisor) 65 x.Mul(y, x) 66 x.Add(parent.Difficulty, x) 67 68 // testnet no minimum 69 if chainID == params.MainnetChainConfig.ChainId.Uint64() { 70 x = math.BigMax(x, params.MinimumDifficultyGenesis) 71 } 72 return x 73 } 74 75 // calcDifficultyHF1 is the difficulty adjustment algorithm. It returns 76 // the difficulty that a new block should have when created at time given the 77 // parent block's time and difficulty. The calculation uses modified Homestead rules. 78 // It is flawed, target 10 seconds 79 func calcDifficultyHF1(time uint64, parent *types.Header, chainID uint64) *big.Int { 80 bigTime := new(big.Int).SetUint64(time) 81 bigParentTime := new(big.Int).Set(parent.Time) 82 83 // holds intermediate values to make the algo easier to read & audit 84 x := new(big.Int) 85 y := new(big.Int) 86 87 // 1 - (block_timestamp - parent_timestamp) // 10 88 x.Sub(bigTime, bigParentTime) 89 x.Div(x, big10) 90 x.Sub(big1, x) 91 92 // max(1 - (block_timestamp - parent_timestamp) // 10, -99) 93 if x.Cmp(bigMinus99) < 0 { 94 x.Set(bigMinus99) 95 } 96 // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) 97 y.Div(parent.Difficulty, params.DifficultyBoundDivisor) 98 x.Mul(y, x) 99 x.Add(parent.Difficulty, x) 100 101 // minimum difficulty can ever be (before exponential factor) 102 if chainID == params.MainnetChainConfig.ChainId.Uint64() { 103 x = math.BigMax(x, params.MinimumDifficultyHF1) 104 } 105 return x 106 } 107 108 // calcDifficultyHFX combines all difficulty algorithms 109 func calcDifficultyHFX(config *params.ChainConfig, time uint64, parent, grandparent *types.Header) *big.Int { 110 var ( 111 diff = new(big.Int) 112 next = new(big.Int).Add(parent.Number, big1) 113 chainID = config.ChainId.Uint64() 114 hf = config.UseHF(next) 115 adjust *big.Int 116 bigTime = new(big.Int) 117 bigParentTime = new(big.Int) 118 limit = params.DurationLimitHF6 // target 240 seconds 119 min = params.MinimumDifficultyHF5 120 mainnet = params.MainnetChainConfig.ChainId.Uint64() == chainID // bool 121 ethnet = params.EthnetChainConfig.ChainId.Uint64() == chainID // bool 122 ) 123 if config == params.Testnet3ChainConfig { 124 return calcDifficultyGrandparent(time, parent, grandparent, hf, chainID) 125 } 126 if ethnet { 127 return EthCalcDifficulty(config, time, parent) 128 } 129 if !mainnet { 130 min = params.MinimumDifficultyHF5Testnet 131 } 132 133 if hf > params.KnownHF { 134 panic("unknown HF not implemented") 135 } 136 137 switch hf { 138 case 9: 139 return calcDifficultyGrandparent(time, parent, grandparent, hf, chainID) 140 case 8: 141 if next.Cmp(config.GetHF(8)) == 0 && mainnet { 142 return params.MinimumDifficultyHF5 143 } 144 if next.Cmp(config.GetHF(8)) == 0 && !mainnet { 145 return params.MinimumDifficultyHF8Testnet 146 } 147 adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisorHF8) 148 if !mainnet { 149 adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisorHF8Testnet) 150 min = params.MinimumDifficultyHF8Testnet 151 } 152 case 6, 7: 153 adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisorHF6) 154 case 5: 155 if next.Cmp(config.GetHF(5)) == 0 && mainnet { 156 return params.MinimumDifficultyHF5 157 } 158 if next.Cmp(config.GetHF(5)) == 0 && !mainnet { 159 return params.MinimumDifficultyHF5Testnet 160 } 161 limit = params.DurationLimit // not accurate, fixed in hf6 162 adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisorHF5) 163 if mainnet { 164 min = params.MinimumDifficultyHF5 165 } 166 case 3, 4: 167 limit = params.DurationLimit // not accurate, fixed in hf6 168 adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) 169 if mainnet { 170 min = params.MinimumDifficultyHF3 171 } 172 case 2: 173 limit = params.DurationLimit // not accurate, fixed in hf6 174 adjust = new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) 175 if mainnet { 176 min = params.MinimumDifficultyHF1 177 } 178 case 1: 179 return calcDifficultyHF1(time, parent, chainID) 180 case 0: 181 return calcDifficultyStarting(time, parent, chainID) 182 default: 183 panic("calcDifficulty: invalid hf") 184 } 185 186 bigTime.SetUint64(time) 187 bigParentTime.Set(parent.Time) 188 189 // calculate difficulty 190 if bigTime.Sub(bigTime, bigParentTime).Cmp(limit) < 0 { 191 diff.Add(parent.Difficulty, adjust) 192 } else { 193 diff.Sub(parent.Difficulty, adjust) 194 } 195 196 if diff.Cmp(min) < 0 { 197 diff.Set(min) 198 } 199 200 return diff 201 } 202 203 // calcDifficultyGrandparent experimental 204 func calcDifficultyGrandparent(time uint64, parent, grandparent *types.Header, hf int, chainID uint64) *big.Int { 205 if grandparent == nil { 206 return new(big.Int).Set(parent.Difficulty) 207 } 208 bigGrandparentTime := new(big.Int).Set(grandparent.Time) 209 bigParentTime := new(big.Int).Set(parent.Time) 210 if bigParentTime.Cmp(bigGrandparentTime) <= 0 { 211 panic("invalid code") 212 } 213 // holds intermediate values to make the algo easier to read & audit 214 x := new(big.Int) 215 y := new(big.Int) 216 217 divisor := params.DifficultyBoundDivisorHF5 218 219 // 1 - (block_timestamp - parent_timestamp) // 240 220 x.Sub(bigParentTime, bigGrandparentTime) 221 x.Div(x, big240) 222 x.Sub(big1, x) 223 224 // max(1 - (block_timestamp - parent_timestamp) // 240, -99) 225 if x.Cmp(bigMinus99) < 0 { 226 x.Set(bigMinus99) 227 } 228 229 if grandparent.Difficulty.Cmp(big10000) < 0 { 230 divisor = params.DifficultyBoundDivisorHF5 231 } else { 232 divisor = params.DifficultyBoundDivisorHF8 233 } 234 // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) 235 y.Div(grandparent.Difficulty, divisor) 236 x.Mul(y, x) 237 x.Add(grandparent.Difficulty, x) 238 239 // minimum difficulty can ever be (before exponential factor) 240 if chainID == params.MainnetChainConfig.ChainId.Uint64() { 241 x = math.BigMax(x, params.MinimumDifficultyHF5) 242 } else { 243 x = math.BigMax(x, params.MinimumDifficultyHF5Testnet) 244 } 245 return x 246 } 247 248 var big100 = big.NewInt(100) 249 var big1000 = big.NewInt(1000) 250 var big20 = big.NewInt(20) 251 252 func calcDifficultyTestnet3(time uint64, parent, grandparent *types.Header) *big.Int { 253 if grandparent == nil { 254 return new(big.Int).Set(parent.Difficulty) 255 } 256 bigTime := new(big.Int).SetUint64(time) 257 bigParentTime := new(big.Int).Set(parent.Time) 258 bigGParentTime := new(big.Int).Set(grandparent.Time) 259 difference := new(big.Int).Sub(bigTime, bigParentTime) 260 gdifference := new(big.Int).Sub(bigGParentTime, bigParentTime) 261 if difference.Cmp(big10) < 0 && gdifference.Cmp(big10) < 0 { 262 return new(big.Int).Add(parent.Difficulty, big1000) 263 } 264 if difference.Cmp(big20) > 0 && gdifference.Cmp(big20) > 0 { 265 return new(big.Int).Sub(parent.Difficulty, big1000) 266 } 267 if difference.Cmp(big100) > 0 && gdifference.Cmp(big100) > 0 { 268 return new(big.Int).Quo(parent.Difficulty, big2) 269 } 270 return new(big.Int).Set(parent.Difficulty) 271 }