github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/consensus/difficulty/difficulty.go (about) 1 package difficulty 2 3 import ( 4 "math/big" 5 6 "github.com/bytom/bytom/consensus" 7 "github.com/bytom/bytom/mining/tensority" 8 "github.com/bytom/bytom/protocol/bc" 9 "github.com/bytom/bytom/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 }