github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/common/types.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package common 13 14 import ( 15 "encoding/hex" 16 "fmt" 17 "math/big" 18 "math/rand" 19 "reflect" 20 21 "github.com/Sberex/go-sberex/common/hexutil" 22 "github.com/Sberex/go-sberex/crypto/sha3" 23 ) 24 25 const ( 26 HashLength = 32 27 AddressLength = 20 28 ) 29 30 var ( 31 hashT = reflect.TypeOf(Hash{}) 32 addressT = reflect.TypeOf(Address{}) 33 ) 34 35 // Hash represents the 32 byte Keccak256 hash of arbitrary data. 36 type Hash [HashLength]byte 37 38 func BytesToHash(b []byte) Hash { 39 var h Hash 40 h.SetBytes(b) 41 return h 42 } 43 func StringToHash(s string) Hash { return BytesToHash([]byte(s)) } 44 func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } 45 func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } 46 47 // Get the string representation of the underlying hash 48 func (h Hash) Str() string { return string(h[:]) } 49 func (h Hash) Bytes() []byte { return h[:] } 50 func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) } 51 func (h Hash) Hex() string { return hexutil.Encode(h[:]) } 52 53 // TerminalString implements log.TerminalStringer, formatting a string for console 54 // output during logging. 55 func (h Hash) TerminalString() string { 56 return fmt.Sprintf("%x…%x", h[:3], h[29:]) 57 } 58 59 // String implements the stringer interface and is used also by the logger when 60 // doing full logging into a file. 61 func (h Hash) String() string { 62 return h.Hex() 63 } 64 65 // Format implements fmt.Formatter, forcing the byte slice to be formatted as is, 66 // without going through the stringer interface used for logging. 67 func (h Hash) Format(s fmt.State, c rune) { 68 fmt.Fprintf(s, "%"+string(c), h[:]) 69 } 70 71 // UnmarshalText parses a hash in hex syntax. 72 func (h *Hash) UnmarshalText(input []byte) error { 73 return hexutil.UnmarshalFixedText("Hash", input, h[:]) 74 } 75 76 // UnmarshalJSON parses a hash in hex syntax. 77 func (h *Hash) UnmarshalJSON(input []byte) error { 78 return hexutil.UnmarshalFixedJSON(hashT, input, h[:]) 79 } 80 81 // MarshalText returns the hex representation of h. 82 func (h Hash) MarshalText() ([]byte, error) { 83 return hexutil.Bytes(h[:]).MarshalText() 84 } 85 86 // Sets the hash to the value of b. If b is larger than len(h), 'b' will be cropped (from the left). 87 func (h *Hash) SetBytes(b []byte) { 88 if len(b) > len(h) { 89 b = b[len(b)-HashLength:] 90 } 91 92 copy(h[HashLength-len(b):], b) 93 } 94 95 // Set string `s` to h. If s is larger than len(h) s will be cropped (from left) to fit. 96 func (h *Hash) SetString(s string) { h.SetBytes([]byte(s)) } 97 98 // Sets h to other 99 func (h *Hash) Set(other Hash) { 100 for i, v := range other { 101 h[i] = v 102 } 103 } 104 105 // Generate implements testing/quick.Generator. 106 func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value { 107 m := rand.Intn(len(h)) 108 for i := len(h) - 1; i > m; i-- { 109 h[i] = byte(rand.Uint32()) 110 } 111 return reflect.ValueOf(h) 112 } 113 114 func EmptyHash(h Hash) bool { 115 return h == Hash{} 116 } 117 118 // UnprefixedHash allows marshaling a Hash without 0x prefix. 119 type UnprefixedHash Hash 120 121 // UnmarshalText decodes the hash from hex. The 0x prefix is optional. 122 func (h *UnprefixedHash) UnmarshalText(input []byte) error { 123 return hexutil.UnmarshalFixedUnprefixedText("UnprefixedHash", input, h[:]) 124 } 125 126 // MarshalText encodes the hash as hex. 127 func (h UnprefixedHash) MarshalText() ([]byte, error) { 128 return []byte(hex.EncodeToString(h[:])), nil 129 } 130 131 /////////// Address 132 133 // Address represents the 20 byte address of an Sberex account. 134 type Address [AddressLength]byte 135 136 func BytesToAddress(b []byte) Address { 137 var a Address 138 a.SetBytes(b) 139 return a 140 } 141 func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } 142 func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } 143 func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } 144 145 // IsHexAddress verifies whether a string can represent a valid hex-encoded 146 // Sberex address or not. 147 func IsHexAddress(s string) bool { 148 if hasHexPrefix(s) { 149 s = s[2:] 150 } 151 return len(s) == 2*AddressLength && isHex(s) 152 } 153 154 // Get the string representation of the underlying address 155 func (a Address) Str() string { return string(a[:]) } 156 func (a Address) Bytes() []byte { return a[:] } 157 func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) } 158 func (a Address) Hash() Hash { return BytesToHash(a[:]) } 159 160 // Hex returns an EIP55-compliant hex string representation of the address. 161 func (a Address) Hex() string { 162 unchecksummed := hex.EncodeToString(a[:]) 163 sha := sha3.NewKeccak256() 164 sha.Write([]byte(unchecksummed)) 165 hash := sha.Sum(nil) 166 167 result := []byte(unchecksummed) 168 for i := 0; i < len(result); i++ { 169 hashByte := hash[i/2] 170 if i%2 == 0 { 171 hashByte = hashByte >> 4 172 } else { 173 hashByte &= 0xf 174 } 175 if result[i] > '9' && hashByte > 7 { 176 result[i] -= 32 177 } 178 } 179 return "0x" + string(result) 180 } 181 182 // String implements the stringer interface and is used also by the logger. 183 func (a Address) String() string { 184 return a.Hex() 185 } 186 187 // Format implements fmt.Formatter, forcing the byte slice to be formatted as is, 188 // without going through the stringer interface used for logging. 189 func (a Address) Format(s fmt.State, c rune) { 190 fmt.Fprintf(s, "%"+string(c), a[:]) 191 } 192 193 // Sets the address to the value of b. If b is larger than len(a) it will panic 194 func (a *Address) SetBytes(b []byte) { 195 if len(b) > len(a) { 196 b = b[len(b)-AddressLength:] 197 } 198 copy(a[AddressLength-len(b):], b) 199 } 200 201 // Set string `s` to a. If s is larger than len(a) it will panic 202 func (a *Address) SetString(s string) { a.SetBytes([]byte(s)) } 203 204 // Sets a to other 205 func (a *Address) Set(other Address) { 206 for i, v := range other { 207 a[i] = v 208 } 209 } 210 211 // MarshalText returns the hex representation of a. 212 func (a Address) MarshalText() ([]byte, error) { 213 return hexutil.Bytes(a[:]).MarshalText() 214 } 215 216 // UnmarshalText parses a hash in hex syntax. 217 func (a *Address) UnmarshalText(input []byte) error { 218 return hexutil.UnmarshalFixedText("Address", input, a[:]) 219 } 220 221 // UnmarshalJSON parses a hash in hex syntax. 222 func (a *Address) UnmarshalJSON(input []byte) error { 223 return hexutil.UnmarshalFixedJSON(addressT, input, a[:]) 224 } 225 226 // UnprefixedHash allows marshaling an Address without 0x prefix. 227 type UnprefixedAddress Address 228 229 // UnmarshalText decodes the address from hex. The 0x prefix is optional. 230 func (a *UnprefixedAddress) UnmarshalText(input []byte) error { 231 return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:]) 232 } 233 234 // MarshalText encodes the address as hex. 235 func (a UnprefixedAddress) MarshalText() ([]byte, error) { 236 return []byte(hex.EncodeToString(a[:])), nil 237 }