OSDN Git Service

Merge remote-tracking branch 'origin/dev' into wallet
[bytom/bytom.git] / consensus / difficulty.go
1 package consensus
2
3 // HashToBig converts a *bc.Hash into a big.Int that can be used to
4 import (
5         "math/big"
6
7         "github.com/bytom/protocol/bc"
8         "github.com/bytom/protocol/bc/legacy"
9 )
10
11 // perform math comparisons.
12 func HashToBig(hash *bc.Hash) *big.Int {
13         buf := hash.Byte32()
14         blen := len(buf)
15         for i := 0; i < blen/2; i++ {
16                 buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
17         }
18
19         return new(big.Int).SetBytes(buf[:])
20 }
21
22 // CompactToBig converts a compact representation of a whole number N to an
23 // unsigned 64-bit number.  The representation is similar to IEEE754 floating
24 // point numbers.
25 //
26 //      -------------------------------------------------
27 //      |   Exponent     |    Sign    |    Mantissa     |
28 //      -------------------------------------------------
29 //      | 8 bits [63-56] | 1 bit [55] | 55 bits [54-00] |
30 //      -------------------------------------------------
31 //
32 //      N = (-1^sign) * mantissa * 256^(exponent-3)
33 func CompactToBig(compact uint64) *big.Int {
34         // Extract the mantissa, sign bit, and exponent.
35         mantissa := compact & 0x007fffffffffffff
36         isNegative := compact&0x0080000000000000 != 0
37         exponent := uint(compact >> 56)
38
39         var bn *big.Int
40         if exponent <= 3 {
41                 mantissa >>= 8 * (3 - exponent)
42                 bn = big.NewInt(int64(mantissa))
43         } else {
44                 bn = big.NewInt(int64(mantissa))
45                 bn.Lsh(bn, 8*(exponent-3))
46         }
47
48         if isNegative {
49                 bn = bn.Neg(bn)
50         }
51
52         return bn
53 }
54
55 // BigToCompact converts a whole number N to a compact representation using
56 // an unsigned 64-bit number
57 func BigToCompact(n *big.Int) uint64 {
58         if n.Sign() == 0 {
59                 return 0
60         }
61
62         var mantissa uint64
63         exponent := uint(len(n.Bytes()))
64         if exponent <= 3 {
65                 mantissa = uint64(n.Bits()[0])
66                 mantissa <<= 8 * (3 - exponent)
67         } else {
68                 tn := new(big.Int).Set(n)
69                 mantissa = uint64(tn.Rsh(tn, 8*(exponent-3)).Bits()[0])
70         }
71
72         if mantissa&0x0080000000000000 != 0 {
73                 mantissa >>= 8
74                 exponent++
75         }
76
77         compact := uint64(exponent<<56) | mantissa
78         if n.Sign() < 0 {
79                 compact |= 0x0080000000000000
80         }
81         return compact
82 }
83
84 func CheckProofOfWork(hash *bc.Hash, bits uint64) bool {
85         return HashToBig(hash).Cmp(CompactToBig(bits)) <= 0
86 }
87
88 func CalcNextRequiredDifficulty(lastBH, compareBH *legacy.BlockHeader) uint64 {
89         if lastBH == nil {
90                 return powMinBits
91         } else if (lastBH.Height) % BlocksPerRetarget != 0 {
92                 return lastBH.Bits
93         }
94
95         targetTimeSpan := int64(BlocksPerRetarget * targetSecondsPerBlock)
96         actualTimespan := int64(lastBH.Time().Sub(compareBH.Time()).Seconds())
97
98         oldTarget := CompactToBig(lastBH.Bits)
99         newTarget := new(big.Int).Mul(oldTarget, big.NewInt(actualTimespan))
100         newTarget.Div(newTarget, big.NewInt(targetTimeSpan))
101         newTargetBits := BigToCompact(newTarget)
102
103         return newTargetBits
104 }