1// SPDX-License-Identifier: ISC 2// Copyright (c) 2014-2020 Bitmark Inc. 3// Use of this source code is governed by an ISC 4// license that can be found in the LICENSE file. 5 6package difficulty 7 8import ( 9 "encoding/binary" 10 "encoding/hex" 11 "fmt" 12 "math" 13 "math/big" 14 "sync" 15 16 "github.com/bitmark-inc/logger" 17) 18 19// the default values 20const ( 21 OneUint64 uint64 = 0x00ffffffffffffff 22 minimumReciprocal float64 = 1.0 23 ExpectedBlockSpacingInSecond = 2 * 60 24 AdjustTimespanInBlocks = 200 25 adjustTimespanInSecond = ExpectedBlockSpacingInSecond * AdjustTimespanInBlocks 26 nextDifficultyRatioUpperbound = 4 27 nextDifficultyRaioLowerbound = 0.25 28 firstBlock = 2 29 minMutiplyOfTimespanPeriod = 2 30 defaultEmptyBits = 8 31) 32 33// Difficulty - Type for difficulty 34// 35// bits is encoded as: 36// 8 bit exponent, 37// 57 bit mantissa normalised so msb is '1' and omitted 38// mantissa is shifted by exponent+8 39// examples: 40// the "One" value: 00 ff ff ff ff ff ff ff 41// represents the 256 bit value: 00ff ffff ffff ffff 8000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 42// value: 01 ff ff ff ff ff ff ff 43// represents the 256 bit value: 007f ffff ffff ffff c000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 44type Difficulty struct { 45 m *sync.RWMutex // pointer since MarshallJSON is pass by value 46 big big.Int // difficulty value: 256 bit integer expanded from bits 47 reciprocal float64 // cache: floating point reciprocal difficulty 48 bits uint64 // cache: compat difficulty (encoded value) 49} 50 51// Current - current difficulty 52var Current = New() 53 54// difficulty of 1 as 256 bit big endian value 55var constOne = []byte{ 56 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 57 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60} 61 62var one big.Int // for reciprocal calculation 63var floatOne big.Float // for reciprocal calculation 64 65// on startup 66func init() { 67 one.SetBytes(constOne) 68 floatOne.SetInt(&one) 69 Current.SetBits(OneUint64) 70} 71 72// New - create a difficulty with the largest possible value 73// which is the easiest for the miners and has the fewest leading zeros 74func New() *Difficulty { 75 d := new(Difficulty) 76 return d.internalReset() 77} 78 79// Value - difficulty value (floating point, it's Pdiff value) 80// This value is a reciprocal, difficulty.value = 1 / difficulty.bits 81func (difficulty *Difficulty) Value() float64 { 82 difficulty.m.RLock() 83 defer difficulty.m.RUnlock() 84 return difficulty.reciprocal 85} 86 87// Bits - Get difficulty as short packed value 88func (difficulty *Difficulty) Bits() uint64 { 89 difficulty.m.RLock() 90 defer difficulty.m.RUnlock() 91 return difficulty.bits 92} 93 94// String - Get difficulty as the big endian hex encodes short packed value 95func (difficulty *Difficulty) String() string { 96 difficulty.m.RLock() 97 defer difficulty.m.RUnlock() 98 return fmt.Sprintf("%016x", difficulty.bits) 99} 100 101// GoString - for the %#v format use 256 bit value 102func (difficulty *Difficulty) GoString() string { 103 return fmt.Sprintf("%064x", difficulty.BigInt()) 104} 105 106// BigInt - convert a uint64 difficulty value to a big.Int 107func (difficulty *Difficulty) BigInt() *big.Int { 108 difficulty.m.RLock() 109 defer difficulty.m.RUnlock() 110 d := new(big.Int) 111 return d.Set(&difficulty.big) 112} 113 114// reset difficulty to minimum 115// ensure write locked before calling this 116func (difficulty *Difficulty) internalReset() *Difficulty { 117 if nil == difficulty.m { 118 difficulty.m = new(sync.RWMutex) 119 } 120 difficulty.big.Set(&one) 121 difficulty.reciprocal = minimumReciprocal 122 difficulty.bits = OneUint64 123 return difficulty 124} 125 126// SetBits - set from a 64 bit word (bits) 127func (difficulty *Difficulty) SetBits(u uint64) *Difficulty { 128 129 // quick setup for default 130 if OneUint64 == u { 131 difficulty.m.Lock() 132 defer difficulty.m.Unlock() 133 return difficulty.internalReset() 134 } 135 136 exponent := uint(u>>56) & 0xff 137 mantissa := u&0x00ffffffffffffff | 0x0100000000000000 // include hidden bit 138 139 // check for exponent overflow 140 if exponent >= 0xc0 { 141 logger.Criticalf("difficulty.SetBits(0x%16x) invalid value", u) 142 logger.Panic("difficulty.SetBits: failed") 143 } 144 d := big.NewInt(0) 145 d.SetUint64(mantissa) 146 d.Lsh(d, 256-65-exponent) // account for hidden 56th bit 147 148 // compute 1/d 149 denominator := new(big.Float) 150 denominator.SetInt(d) 151 q := new(big.Float) 152 result, _ := q.Quo(&floatOne, denominator).Float64() 153 154 // modify cache 155 difficulty.m.Lock() 156 defer difficulty.m.Unlock() 157 158 difficulty.big.Set(d) 159 difficulty.reciprocal = result 160 difficulty.bits = u 161 162 return difficulty 163} 164 165// Set - set difficulty value 166func (difficulty *Difficulty) Set(f float64) { 167 difficulty.m.Lock() 168 defer difficulty.m.Unlock() 169 difficulty.convertDifficultyIntoReciprocal(f) 170} 171 172// ensure write locked before calling this 173func (difficulty *Difficulty) convertDifficultyIntoReciprocal(f float64) float64 { 174 if f < minimumReciprocal { 175 difficulty.internalReset() 176 return difficulty.reciprocal 177 } 178 difficulty.reciprocal = f 179 180 r := new(big.Float) 181 r.SetMode(big.ToPositiveInf).SetPrec(256).SetFloat64(f).Quo(&floatOne, r) 182 183 d, _ := r.Int(&difficulty.big) 184 185 // fmt.Printf("f_1: %s\n", floatOne.Text('f', 80)) 186 // fmt.Printf("rec: %s\n", r.Text('f', 80)) 187 // fmt.Printf("big: %d\n", d) 188 // fmt.Printf("%f\n big: %064x\n", f, d) 189 // fmt.Printf("acc: %s\n", accuracy.String()) 190 191 buffer := d.Bytes() // no more than 32 bytes (256 bits) 192 193 if len(buffer) > 32 { 194 logger.Criticalf("difficulty.convertDifficultyIntoReciprocal(%g) invalid value", f) 195 logger.Panic("difficulty.SetBits: failed - needs more than 256 bits") 196 } 197 198 // first non-zero byte will not exceed 0x7f as bigints are signed 199 // but the above calculation results in an unsigned value 200 // need to extract 56 bits with 1st bit as 1 and compute exponent 201scan_buffer: 202 for i, b := range buffer { 203 if 0 != b { 204 u := uint64(b) << 56 205 if i+1 < len(buffer) { 206 u |= uint64(buffer[i+1]) << 48 207 } 208 if i+2 < len(buffer) { 209 u |= uint64(buffer[i+2]) << 40 210 } 211 if i+3 < len(buffer) { 212 u |= uint64(buffer[i+3]) << 32 213 } 214 if i+4 < len(buffer) { 215 u |= uint64(buffer[i+4]) << 24 216 } 217 if i+5 < len(buffer) { 218 u |= uint64(buffer[i+5]) << 16 219 } 220 if i+6 < len(buffer) { 221 u |= uint64(buffer[i+6]) << 8 222 } 223 if i+7 < len(buffer) { 224 u |= uint64(buffer[i+7]) 225 } 226 227 // compute exponent 228 e := uint64(32-len(buffer)+i)*8 - 1 229 230 // normalise 231 rounder := 0 232 for 0x0100000000000000 != 0xff00000000000000&u { 233 if 1 == u&1 { 234 rounder += 1 235 } 236 u >>= 1 237 e -= 1 238 } 239 240 if rounder > 4 { 241 u += 1 242 } 243 // hide 56th bit and incorporate exponent 244 u = u&0x00ffffffffffffff | e<<56 245 //fmt.Printf("bits: %016x\n", u) 246 247 difficulty.bits = u 248 break scan_buffer 249 } 250 } 251 252 return difficulty.reciprocal 253} 254 255// SetBytes - set the difficulty from little endian bytes 256func (difficulty *Difficulty) SetBytes(b []byte) *Difficulty { 257 258 const byteLength = 8 259 if len(b) != byteLength { 260 logger.Panicf("difficulty.SetBytes: too few bytes expected: %d had: %d", byteLength, len(b)) 261 } 262 263 u := uint64(b[0]) | 264 uint64(b[1])<<8 | 265 uint64(b[2])<<16 | 266 uint64(b[3])<<24 | 267 uint64(b[4])<<32 | 268 uint64(b[5])<<40 | 269 uint64(b[6])<<48 | 270 uint64(b[7])<<56 271 272 return difficulty.SetBits(u) 273} 274 275// MarshalText - convert a difficulty to little endian hex for JSON 276func (difficulty Difficulty) MarshalText() ([]byte, error) { 277 278 bits := make([]byte, 8) 279 binary.LittleEndian.PutUint64(bits, difficulty.bits) 280 281 size := hex.EncodedLen(len(bits)) 282 buffer := make([]byte, size) 283 hex.Encode(buffer, bits) 284 return buffer, nil 285} 286 287// UnmarshalText - convert a difficulty little endian hex string to difficulty value 288func (difficulty *Difficulty) UnmarshalText(s []byte) error { 289 buffer := make([]byte, hex.DecodedLen(len(s))) 290 _, err := hex.Decode(buffer, s) 291 if nil != err { 292 return err 293 } 294 difficulty.internalReset() 295 difficulty.SetBytes(buffer) 296 return nil 297} 298 299// NextDifficultyByPreviousTimespan - next difficulty calculated by previous timespan 300func NextDifficultyByPreviousTimespan(prevTimespanSecond uint64, currentDifficulty float64) float64 { 301 ratio := adjustRatioByLastTimespan(prevTimespanSecond) 302 303 nextDifficulty := ratio * currentDifficulty 304 305 if nextDifficulty < minimumReciprocal { 306 nextDifficulty = minimumReciprocal 307 } 308 309 return nextDifficulty 310} 311 312func adjustRatioByLastTimespan(actualTimespanSecond uint64) float64 { 313 if actualTimespanSecond <= adjustTimespanInSecond>>2 { 314 return nextDifficultyRatioUpperbound 315 } 316 317 if actualTimespanSecond >= adjustTimespanInSecond<<2 { 318 return nextDifficultyRaioLowerbound 319 } 320 return float64(adjustTimespanInSecond) / float64(actualTimespanSecond) 321} 322 323// PrevTimespanBlockBeginAndEnd - previous begin & end block of difficulty timespan 324func PrevTimespanBlockBeginAndEnd(height uint64) (uint64, uint64) { 325 if remainder := height % AdjustTimespanInBlocks; remainder != 0 { 326 return prevBeginBlockWhenAtBeginOfNextTimespan(height - remainder) 327 } 328 return prevBeginBlockWhenAtBeginOfNextTimespan(height) 329} 330 331func prevBeginBlockWhenAtBeginOfNextTimespan(height uint64) (uint64, uint64) { 332 quotient := height / AdjustTimespanInBlocks 333 if quotient >= minMutiplyOfTimespanPeriod { 334 return height - 1 - AdjustTimespanInBlocks, height - 1 335 } 336 337 // below calculation only fits when adjust period in blocks larger than 2 338 end := AdjustTimespanInBlocks - 1 339 if end <= firstBlock { 340 end = AdjustTimespanInBlocks 341 } 342 return uint64(firstBlock), uint64(end) 343} 344 345// Hashrate - calculate hashrate from current difficulty, rounded to 3 digits 346func Hashrate() float64 { 347 zeroBitCount := defaultEmptyBits + math.Log2(Current.Value()) 348 rate := math.Pow(2, zeroBitCount) / ExpectedBlockSpacingInSecond 349 return math.Floor(rate*1000+0.5) / 1000 350} 351