OSDN Git Service

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