git.gammaspectra.live/P2Pool/consensus@v0.0.0-20240403173234-a039820b20c9/types/types.go (about)

     1  package types
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"encoding/binary"
     6  	"encoding/hex"
     7  	"errors"
     8  	fasthex "github.com/tmthrgd/go-hex"
     9  	"runtime"
    10  	"unsafe"
    11  )
    12  
    13  const HashSize = 32
    14  
    15  type Hash [HashSize]byte
    16  
    17  var ZeroHash Hash
    18  
    19  func (h Hash) MarshalJSON() ([]byte, error) {
    20  	var buf [HashSize*2 + 2]byte
    21  	buf[0] = '"'
    22  	buf[HashSize*2+1] = '"'
    23  	fasthex.Encode(buf[1:], h[:])
    24  	return buf[:], nil
    25  }
    26  
    27  func MustHashFromString(s string) Hash {
    28  	if h, err := HashFromString(s); err != nil {
    29  		panic(err)
    30  	} else {
    31  		return h
    32  	}
    33  }
    34  
    35  func HashFromString(s string) (Hash, error) {
    36  	var h Hash
    37  	if buf, err := hex.DecodeString(s); err != nil {
    38  		return h, err
    39  	} else {
    40  		if len(buf) != HashSize {
    41  			return h, errors.New("wrong hash size")
    42  		}
    43  		copy(h[:], buf)
    44  		return h, nil
    45  	}
    46  }
    47  
    48  func HashFromBytes(buf []byte) (h Hash) {
    49  	if len(buf) != HashSize {
    50  		return
    51  	}
    52  	copy(h[:], buf)
    53  	return
    54  }
    55  
    56  // Compare consensus way of comparison
    57  func (h Hash) Compare(other Hash) int {
    58  	//golang might free other otherwise
    59  	defer runtime.KeepAlive(other)
    60  	defer runtime.KeepAlive(h)
    61  	a := unsafe.Slice((*uint64)(unsafe.Pointer(&h)), len(h)/int(unsafe.Sizeof(uint64(0))))
    62  	b := unsafe.Slice((*uint64)(unsafe.Pointer(&other)), len(other)/int(unsafe.Sizeof(uint64(0))))
    63  
    64  	if a[3] < b[3] {
    65  		return -1
    66  	}
    67  	if a[3] > b[3] {
    68  		return 1
    69  	}
    70  
    71  	if a[2] < b[2] {
    72  		return -1
    73  	}
    74  	if a[2] > b[2] {
    75  		return 1
    76  	}
    77  
    78  	if a[1] < b[1] {
    79  		return -1
    80  	}
    81  	if a[1] > b[1] {
    82  		return 1
    83  	}
    84  
    85  	if a[0] < b[0] {
    86  		return -1
    87  	}
    88  	if a[0] > b[0] {
    89  		return 1
    90  	}
    91  
    92  	return 0
    93  }
    94  
    95  func (h Hash) String() string {
    96  	return hex.EncodeToString(h[:])
    97  }
    98  
    99  func (h Hash) Uint64() uint64 {
   100  	return binary.LittleEndian.Uint64(h[:])
   101  }
   102  
   103  func (h *Hash) Scan(src any) error {
   104  	if src == nil {
   105  		return nil
   106  	} else if buf, ok := src.([]byte); ok {
   107  		if len(buf) == 0 {
   108  			return nil
   109  		}
   110  		if len(buf) != HashSize {
   111  			return errors.New("invalid hash size")
   112  		}
   113  		copy((*h)[:], buf)
   114  
   115  		return nil
   116  	}
   117  	return errors.New("invalid type")
   118  }
   119  
   120  func (h *Hash) Value() (driver.Value, error) {
   121  	if *h == ZeroHash {
   122  		return nil, nil
   123  	}
   124  	return (*h)[:], nil
   125  }
   126  
   127  func (h *Hash) UnmarshalJSON(b []byte) error {
   128  	if len(b) == 0 || len(b) == 2 {
   129  		return nil
   130  	}
   131  
   132  	if len(b) != HashSize*2+2 {
   133  		return errors.New("wrong hash size")
   134  	}
   135  
   136  	if _, err := fasthex.Decode(h[:], b[1:len(b)-1]); err != nil {
   137  		return err
   138  	} else {
   139  		return nil
   140  	}
   141  }
   142  
   143  type Bytes []byte
   144  
   145  func (b Bytes) MarshalJSON() ([]byte, error) {
   146  	buf := make([]byte, len(b)*2+2)
   147  	buf[0] = '"'
   148  	buf[len(buf)-1] = '"'
   149  	fasthex.Encode(buf[1:], b)
   150  	return buf, nil
   151  }
   152  
   153  func (b Bytes) String() string {
   154  	return hex.EncodeToString(b)
   155  }
   156  
   157  func (b *Bytes) UnmarshalJSON(buf []byte) error {
   158  	if len(buf) < 2 || (len(buf)%2) != 0 || buf[0] != '"' || buf[len(buf)-1] != '"' {
   159  		return errors.New("invalid bytes")
   160  	}
   161  
   162  	*b = make(Bytes, (len(buf)-2)/2)
   163  
   164  	if _, err := fasthex.Decode(*b, buf[1:len(buf)-1]); err != nil {
   165  		return err
   166  	} else {
   167  		return nil
   168  	}
   169  }