345 lines
7.7 KiB
Go
345 lines
7.7 KiB
Go
package types
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"errors"
|
|
"fmt"
|
|
"git.gammaspectra.live/P2Pool/consensus/v3/utils"
|
|
fasthex "github.com/tmthrgd/go-hex"
|
|
"io"
|
|
"lukechampine.com/uint128"
|
|
"math"
|
|
"math/big"
|
|
"math/bits"
|
|
"strconv"
|
|
"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))
|
|
if d == v {
|
|
return 0
|
|
} else if d.Hi < v.Hi || (d.Hi == v.Hi && d.Lo < v.Lo) {
|
|
return -1
|
|
} else {
|
|
return 1
|
|
}
|
|
}
|
|
|
|
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))
|
|
}
|
|
|
|
// Add All calls can wrap
|
|
func (d Difficulty) Add(v Difficulty) Difficulty {
|
|
//return Difficulty(uint128.Uint128(d).AddWrap(uint128.Uint128(v)))
|
|
lo, carry := bits.Add64(d.Lo, v.Lo, 0)
|
|
hi, _ := bits.Add64(d.Hi, v.Hi, carry)
|
|
return Difficulty{Lo: lo, Hi: hi}
|
|
}
|
|
|
|
// Add64 All calls can wrap
|
|
func (d Difficulty) Add64(v uint64) Difficulty {
|
|
return Difficulty(uint128.Uint128(d).AddWrap64(v))
|
|
}
|
|
|
|
// Sub All calls can wrap
|
|
func (d Difficulty) Sub(v Difficulty) Difficulty {
|
|
return Difficulty(uint128.Uint128(d).SubWrap(uint128.Uint128(v)))
|
|
}
|
|
|
|
// Sub64 All calls can wrap
|
|
func (d Difficulty) Sub64(v uint64) Difficulty {
|
|
return Difficulty(uint128.Uint128(d).SubWrap64(v))
|
|
}
|
|
|
|
// Mul All calls can wrap
|
|
func (d Difficulty) Mul(v Difficulty) Difficulty {
|
|
return Difficulty(uint128.Uint128(d).MulWrap(uint128.Uint128(v)))
|
|
}
|
|
|
|
// Mul64 All calls can wrap
|
|
func (d Difficulty) Mul64(v uint64) Difficulty {
|
|
//return Difficulty(uint128.Uint128(d).MulWrap64(v))
|
|
hi, lo := bits.Mul64(d.Lo, v)
|
|
hi += d.Hi * v
|
|
return Difficulty{Lo: lo, Hi: hi}
|
|
}
|
|
|
|
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) Float64() float64 {
|
|
return float64(d.Lo) + float64(d.Hi)*(float64(math.MaxUint64)+1)
|
|
}
|
|
|
|
func (d Difficulty) MarshalJSON() ([]byte, error) {
|
|
if d.Hi == 0 {
|
|
return []byte(strconv.FormatUint(d.Lo, 10)), nil
|
|
}
|
|
|
|
var encodeBuf [DifficultySize]byte
|
|
d.PutBytesBE(encodeBuf[:])
|
|
|
|
var buf [DifficultySize*2 + 2]byte
|
|
buf[0] = '"'
|
|
buf[DifficultySize*2+1] = '"'
|
|
fasthex.Encode(buf[1:], encodeBuf[:])
|
|
return buf[:], nil
|
|
}
|
|
|
|
func MustDifficultyFromString(s string) Difficulty {
|
|
if d, err := DifficultyFromString(s); err != nil {
|
|
panic(err)
|
|
} else {
|
|
return d
|
|
}
|
|
}
|
|
|
|
func DifficultyFromString(s string) (Difficulty, error) {
|
|
if strings.HasPrefix(s, "0x") {
|
|
if buf, err := fasthex.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 := fasthex.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) (err error) {
|
|
if len(b) == 0 {
|
|
return io.ErrUnexpectedEOF
|
|
}
|
|
|
|
if b[0] == '"' {
|
|
if len(b) < 2 || (len(b)%2) != 0 || b[len(b)-1] != '"' {
|
|
return errors.New("invalid bytes")
|
|
}
|
|
|
|
if len(b) == DifficultySize*2+2 {
|
|
// fast path
|
|
var buf [DifficultySize]byte
|
|
if _, err := fasthex.Decode(buf[:], b[1:len(b)-1]); err != nil {
|
|
return err
|
|
} else {
|
|
*d = DifficultyFromBytes(buf[:])
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if diff, err := DifficultyFromString(string(b[1 : len(b)-1])); err != nil {
|
|
return err
|
|
} else {
|
|
*d = diff
|
|
|
|
return nil
|
|
}
|
|
} else {
|
|
// Difficulty as uint64
|
|
if d.Lo, err = utils.ParseUint64(b); err != nil {
|
|
// Fallback to big int if number is out of range
|
|
if errors.Is(err, strconv.ErrRange) {
|
|
var bInt big.Int
|
|
if err = bInt.UnmarshalText(b); err != nil {
|
|
return err
|
|
} else {
|
|
//recover bigint panics
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
if err = e.(error); err == nil {
|
|
err = fmt.Errorf("panic: %v", e)
|
|
}
|
|
}
|
|
}()
|
|
*d = Difficulty(uint128.FromBig(&bInt))
|
|
}
|
|
}
|
|
return err
|
|
} else {
|
|
d.Hi = 0
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func (d Difficulty) Bytes() []byte {
|
|
var buf [DifficultySize]byte
|
|
d.PutBytesBE(buf[:])
|
|
return buf[:]
|
|
}
|
|
|
|
func (d Difficulty) String() string {
|
|
return fasthex.EncodeToString(d.Bytes())
|
|
}
|
|
|
|
func (d Difficulty) StringNumeric() string {
|
|
return uint128.Uint128(d).String()
|
|
}
|
|
|
|
func (d *Difficulty) Scan(src any) error {
|
|
if src == nil {
|
|
return nil
|
|
} else if buf, ok := src.([]byte); ok {
|
|
if len(buf) == 0 {
|
|
return nil
|
|
}
|
|
|
|
if len(buf) != DifficultySize {
|
|
return errors.New("invalid difficulty size")
|
|
}
|
|
|
|
*d = DifficultyFromBytes(buf)
|
|
|
|
return nil
|
|
}
|
|
return errors.New("invalid type")
|
|
}
|
|
|
|
func (d *Difficulty) Value() (driver.Value, error) {
|
|
return d.Bytes(), nil
|
|
}
|