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