OSDN Git Service

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