github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/types/target.go (about)

     1  package types
     2  
     3  // target.go defines the target type and implements a few helper functions for
     4  // manipulating the target type.
     5  
     6  import (
     7  	"errors"
     8  	"math/big"
     9  
    10  	"github.com/NebulousLabs/Sia/build"
    11  	"github.com/NebulousLabs/Sia/crypto"
    12  )
    13  
    14  type (
    15  	// A Target is a hash that a block's ID must be "less than" in order for
    16  	// the block to be considered valid. Miners vary the block's 'Nonce' field
    17  	// in order to brute-force such an ID. The inverse of a Target is called
    18  	// the "difficulty," because it is proportional to the amount of time
    19  	// required to brute-force the Target.
    20  	Target crypto.Hash
    21  )
    22  
    23  var (
    24  	ErrNegativeTarget = errors.New("negative value used when converting to target")
    25  )
    26  
    27  // AddDifficulties returns the resulting target with the difficulty of 'x' and
    28  // 'y' are added together. Note that the difficulty is the inverse of the
    29  // target. The sum is defined by:
    30  //		sum(x, y) = 1/(1/x + 1/y)
    31  func (x Target) AddDifficulties(y Target) (t Target) {
    32  	sumDifficulty := new(big.Rat).Add(x.Inverse(), y.Inverse())
    33  	return RatToTarget(new(big.Rat).Inv(sumDifficulty))
    34  }
    35  
    36  // Cmp compares the difficulties of two targets. Note that the difficulty is
    37  // the inverse of the target. The results are as follows:
    38  //		-1 if x <  y
    39  //		 0 if x == y
    40  //		+1 if x >  y
    41  func (x Target) Cmp(y Target) int {
    42  	return x.Int().Cmp(y.Int())
    43  }
    44  
    45  // Difficulty returns the difficulty associated with a given target.
    46  func (t Target) Difficulty() Currency {
    47  	if t == (Target{}) {
    48  		return NewCurrency(RootDepth.Int())
    49  	}
    50  	return NewCurrency(new(big.Int).Div(RootDepth.Int(), t.Int()))
    51  }
    52  
    53  // Int converts a Target to a big.Int.
    54  func (t Target) Int() *big.Int {
    55  	return new(big.Int).SetBytes(t[:])
    56  }
    57  
    58  // IntToTarget converts a big.Int to a Target. Negative inputs trigger a panic.
    59  func IntToTarget(i *big.Int) (t Target) {
    60  	// Check for negatives.
    61  	if i.Sign() < 0 {
    62  		if build.DEBUG {
    63  			panic(ErrNegativeTarget)
    64  		}
    65  	} else {
    66  		// In the event of overflow, return the maximum.
    67  		if i.BitLen() > 256 {
    68  			return RootDepth
    69  		}
    70  		b := i.Bytes()
    71  		offset := len(t[:]) - len(b)
    72  		copy(t[offset:], b)
    73  	}
    74  	return
    75  }
    76  
    77  // Inverse returns the inverse of a Target as a big.Rat
    78  func (t Target) Inverse() *big.Rat {
    79  	return new(big.Rat).Inv(t.Rat())
    80  }
    81  
    82  // Mul multiplies the difficulty of a target by y. The product is defined by:
    83  //		y / x
    84  func (x Target) MulDifficulty(y *big.Rat) (t Target) {
    85  	product := new(big.Rat).Mul(y, x.Inverse())
    86  	product = product.Inv(product)
    87  	return RatToTarget(product)
    88  }
    89  
    90  // Rat converts a Target to a big.Rat.
    91  func (t Target) Rat() *big.Rat {
    92  	return new(big.Rat).SetInt(t.Int())
    93  }
    94  
    95  // RatToTarget converts a big.Rat to a Target.
    96  func RatToTarget(r *big.Rat) (t Target) {
    97  	if r.Num().Sign() < 0 {
    98  		if build.DEBUG {
    99  			panic(ErrNegativeTarget)
   100  		}
   101  	} else {
   102  		i := new(big.Int).Div(r.Num(), r.Denom())
   103  		t = IntToTarget(i)
   104  	}
   105  	return
   106  }
   107  
   108  // SubtractDifficulties returns the resulting target with the difficulty of 'x'
   109  // is subtracted from the target with difficulty 'y'. Note that the difficulty
   110  // is the inverse of the target. The difference is defined by:
   111  //		sum(x, y) = 1/(1/x - 1/y)
   112  func (x Target) SubtractDifficulties(y Target) (t Target) {
   113  	sumDifficulty := new(big.Rat).Sub(x.Inverse(), y.Inverse())
   114  	return RatToTarget(new(big.Rat).Inv(sumDifficulty))
   115  }