consensus/types/difficulty.go
2023-03-25 10:49:08 +01:00

279 lines
6.6 KiB
Go

package types
import (
"bytes"
"encoding/hex"
"encoding/json"
"errors"
"github.com/holiman/uint256"
"lukechampine.com/uint128"
"math/big"
"math/bits"
"strings"
)
const DifficultySize = 16
var ZeroDifficulty = Difficulty(uint128.Zero)
var MaxDifficulty = Difficulty(uint128.Max)
type Difficulty uint128.Uint128
func (d Difficulty) IsZero() bool {
return uint128.Uint128(d).IsZero()
}
func (d Difficulty) Equals(v Difficulty) bool {
return uint128.Uint128(d).Equals(uint128.Uint128(v))
}
func (d Difficulty) Equals64(v uint64) bool {
return uint128.Uint128(d).Equals64(v)
}
func (d Difficulty) Cmp(v Difficulty) int {
return uint128.Uint128(d).Cmp(uint128.Uint128(v))
}
func (d Difficulty) Cmp64(v uint64) int {
return uint128.Uint128(d).Cmp64(v)
}
func (d Difficulty) And(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).And(uint128.Uint128(v)))
}
func (d Difficulty) And64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).And64(v))
}
func (d Difficulty) Or(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).Or(uint128.Uint128(v)))
}
func (d Difficulty) Or64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).Or64(v))
}
func (d Difficulty) Xor(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).Xor(uint128.Uint128(v)))
}
func (d Difficulty) Xor64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).Xor64(v))
}
func (d Difficulty) Add(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).Add(uint128.Uint128(v)))
}
func (d Difficulty) AddWrap(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).AddWrap(uint128.Uint128(v)))
}
func (d Difficulty) Add64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).Add64(v))
}
func (d Difficulty) AddWrap64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).AddWrap64(v))
}
func (d Difficulty) Sub(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).Sub(uint128.Uint128(v)))
}
func (d Difficulty) SubWrap(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).SubWrap(uint128.Uint128(v)))
}
func (d Difficulty) Sub64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).Sub64(v))
}
func (d Difficulty) SubWrap64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).SubWrap64(v))
}
func (d Difficulty) Mul(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).Mul(uint128.Uint128(v)))
}
func (d Difficulty) MulWrap(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).MulWrap(uint128.Uint128(v)))
}
func (d Difficulty) Mul64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).Mul64(v))
}
func (d Difficulty) MulWrap64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).MulWrap64(v))
}
func (d Difficulty) Div(v Difficulty) Difficulty {
return Difficulty(uint128.Uint128(d).Div(uint128.Uint128(v)))
}
func (d Difficulty) Div64(v uint64) Difficulty {
return Difficulty(uint128.Uint128(d).Div64(v))
}
func (d Difficulty) QuoRem(v Difficulty) (q, r Difficulty) {
qq, rr := uint128.Uint128(d).QuoRem(uint128.Uint128(v))
return Difficulty(qq), Difficulty(rr)
}
func (d Difficulty) QuoRem64(v uint64) (q Difficulty, r uint64) {
qq, rr := uint128.Uint128(d).QuoRem64(v)
return Difficulty(qq), rr
}
func (d Difficulty) Mod(v Difficulty) (r Difficulty) {
return Difficulty(uint128.Uint128(d).Mod(uint128.Uint128(v)))
}
func (d Difficulty) Mod64(v uint64) (r uint64) {
return uint128.Uint128(d).Mod64(v)
}
func (d Difficulty) Lsh(n uint) (s Difficulty) {
return Difficulty(uint128.Uint128(d).Lsh(n))
}
func (d Difficulty) Rsh(n uint) (s Difficulty) {
return Difficulty(uint128.Uint128(d).Rsh(n))
}
func (d Difficulty) LeadingZeros() int {
return uint128.Uint128(d).LeadingZeros()
}
func (d Difficulty) TrailingZeros() int {
return uint128.Uint128(d).TrailingZeros()
}
func (d Difficulty) OnesCount() int {
return uint128.Uint128(d).OnesCount()
}
func (d Difficulty) RotateLeft(k int) Difficulty {
return Difficulty(uint128.Uint128(d).RotateLeft(k))
}
func (d Difficulty) RotateRight(k int) Difficulty {
return Difficulty(uint128.Uint128(d).RotateRight(k))
}
func (d Difficulty) Reverse() Difficulty {
return Difficulty(uint128.Uint128(d).Reverse())
}
func (d Difficulty) ReverseBytes() Difficulty {
return Difficulty(uint128.Uint128(d).ReverseBytes())
}
func (d Difficulty) Len() int {
return uint128.Uint128(d).Len()
}
func (d Difficulty) PutBytes(b []byte) {
uint128.Uint128(d).PutBytes(b)
}
func (d Difficulty) PutBytesBE(b []byte) {
uint128.Uint128(d).PutBytesBE(b)
}
// Big returns u as a *big.Int.
func (d Difficulty) Big() *big.Int {
return uint128.Uint128(d).Big()
}
func (d Difficulty) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
}
func DifficultyFromString(s string) (Difficulty, error) {
if strings.HasPrefix(s, "0x") {
if buf, err := hex.DecodeString(s[2:]); err != nil {
return ZeroDifficulty, err
} else {
//TODO: check this
var d [DifficultySize]byte
copy(d[DifficultySize-len(buf):], buf)
return DifficultyFromBytes(d[:]), nil
}
} else {
if buf, err := hex.DecodeString(s); err != nil {
return ZeroDifficulty, err
} else {
if len(buf) != DifficultySize {
return ZeroDifficulty, errors.New("wrong difficulty size")
}
return DifficultyFromBytes(buf), nil
}
}
}
func DifficultyFromBytes(buf []byte) Difficulty {
return Difficulty(uint128.FromBytesBE(buf))
}
func NewDifficulty(lo, hi uint64) Difficulty {
return Difficulty{Lo: lo, Hi: hi}
}
func DifficultyFrom64(v uint64) Difficulty {
return NewDifficulty(v, 0)
}
func (d *Difficulty) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
if diff, err := DifficultyFromString(s); err != nil {
return err
} else {
*d = diff
return nil
}
}
func (d Difficulty) Bytes() []byte {
buf := make([]byte, DifficultySize)
d.PutBytesBE(buf)
return buf
}
func (d Difficulty) String() string {
return hex.EncodeToString(d.Bytes())
}
func (d Difficulty) StringNumeric() string {
return uint128.Uint128(d).String()
}
// TODO: remove uint256 dependency as it's unique to this section
var powBase = uint256.NewInt(0).SetBytes32(bytes.Repeat([]byte{0xff}, 32))
func DifficultyFromPoW(powHash Hash) Difficulty {
if powHash == ZeroHash {
return ZeroDifficulty
}
pow := uint256.NewInt(0).SetBytes32(powHash[:])
pow = &uint256.Int{bits.ReverseBytes64(pow[3]), bits.ReverseBytes64(pow[2]), bits.ReverseBytes64(pow[1]), bits.ReverseBytes64(pow[0])}
powResult := uint256.NewInt(0).Div(powBase, pow).Bytes32()
return DifficultyFromBytes(powResult[16:])
}
func (d Difficulty) CheckPoW(pow Hash) bool {
return DifficultyFromPoW(pow).Cmp(d) >= 0
}