-
Notifications
You must be signed in to change notification settings - Fork 3
/
difficulty.go
142 lines (120 loc) · 4.29 KB
/
difficulty.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package difficulty
import (
"math/big"
"github.com/bytom/consensus"
"github.com/bytom/mining/tensority"
"github.com/bytom/protocol/bc"
"github.com/bytom/protocol/bc/types"
)
var (
// bigOne is 1 represented as a big.Int. It is defined here to avoid
// the overhead of creating it multiple times.
bigOne = big.NewInt(1)
// oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid
// the overhead of creating it multiple times.
oneLsh256 = new(big.Int).Lsh(bigOne, 256)
)
// HashToBig convert bc.Hash to a difficulty int
func HashToBig(hash *bc.Hash) *big.Int {
// reverse the bytes of the hash (little-endian) to use it in the big
// package (big-endian)
buf := hash.Byte32()
blen := len(buf)
for i := 0; i < blen/2; i++ {
buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
}
return new(big.Int).SetBytes(buf[:])
}
// CalcWork calculates a work value from difficulty bits.
func CalcWork(bits uint64) *big.Int {
difficultyNum := CompactToBig(bits)
if difficultyNum.Sign() <= 0 {
return big.NewInt(0)
}
// (1 << 256) / (difficultyNum + 1)
denominator := new(big.Int).Add(difficultyNum, bigOne)
return new(big.Int).Div(oneLsh256, denominator)
}
// CompactToBig converts a compact representation of a whole unsigned integer
// N to an big.Int. The representation is similar to IEEE754 floating point
// numbers. Sign is not really being used.
//
// -------------------------------------------------
// | Exponent | Sign | Mantissa |
// -------------------------------------------------
// | 8 bits [63-56] | 1 bit [55] | 55 bits [54-00] |
// -------------------------------------------------
//
// N = (-1^sign) * mantissa * 256^(exponent-3)
// Actually it will be nicer to use 7 instead of 3 for robustness reason.
func CompactToBig(compact uint64) *big.Int {
// Extract the mantissa, sign bit, and exponent.
mantissa := compact & 0x007fffffffffffff
isNegative := compact&0x0080000000000000 != 0
exponent := uint(compact >> 56)
var bn *big.Int
if exponent <= 3 {
mantissa >>= 8 * (3 - exponent)
bn = big.NewInt(int64(mantissa))
} else {
bn = big.NewInt(int64(mantissa))
bn.Lsh(bn, 8*(exponent-3))
}
if isNegative {
bn = bn.Neg(bn)
}
return bn
}
// BigToCompact converts a whole number N to a compact representation using
// an unsigned 64-bit number. Sign is not really being used, but it's kept
// here.
func BigToCompact(n *big.Int) uint64 {
if n.Sign() == 0 {
return 0
}
var mantissa uint64
// Bytes() returns the absolute value of n as a big-endian byte slice
exponent := uint(len(n.Bytes()))
// Bits() returns the absolute value of n as a little-endian uint64 slice
if exponent <= 3 {
mantissa = uint64(n.Bits()[0])
mantissa <<= 8 * (3 - exponent)
} else {
tn := new(big.Int).Set(n)
// Since the base for the exponent is 256, the exponent can be treated
// as the number of bytes to represent the full 256-bit number. And as
// the exponent is treated as the number of bytes, Rsh 8*(exponent-3)
// makes sure that the shifted tn won't occupy more than 8*3=24 bits,
// and can be read from Bits()[0], which is 64-bit
mantissa = uint64(tn.Rsh(tn, 8*(exponent-3)).Bits()[0])
}
if mantissa&0x0080000000000000 != 0 {
mantissa >>= 8
exponent++
}
compact := uint64(exponent)<<56 | mantissa
if n.Sign() < 0 {
compact |= 0x0080000000000000
}
return compact
}
// CheckProofOfWork checks whether the hash is valid for a given difficulty.
func CheckProofOfWork(hash, seed *bc.Hash, bits uint64) bool {
compareHash := tensority.AIHash.Hash(hash, seed)
return HashToBig(compareHash).Cmp(CompactToBig(bits)) <= 0
}
// CalcNextRequiredDifficulty return the difficulty using compact representation
// for next block, when a lower difficulty Int actually reflects a more difficult
// mining progress.
func CalcNextRequiredDifficulty(lastBH, compareBH *types.BlockHeader) uint64 {
if (lastBH.Height)%consensus.BlocksPerRetarget != 0 || lastBH.Height == 0 {
return lastBH.Bits
}
targetTimeSpan := int64(consensus.BlocksPerRetarget * consensus.TargetSecondsPerBlock)
actualTimeSpan := int64(lastBH.Timestamp - compareBH.Timestamp)
oldTarget := CompactToBig(lastBH.Bits)
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(actualTimeSpan))
newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
newTargetBits := BigToCompact(newTarget)
return newTargetBits
}