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 }