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  }