github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/common/types.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package common 19 20 import ( 21 "database/sql/driver" 22 "encoding/hex" 23 "encoding/json" 24 "fmt" 25 "math/big" 26 "math/rand" 27 "reflect" 28 "strings" 29 30 "github.com/AigarNetwork/aigar/common/hexutil" 31 "golang.org/x/crypto/sha3" 32 ) 33 34 // Lengths of hashes and addresses in bytes. 35 const ( 36 // HashLength is the expected length of the hash 37 HashLength = 32 38 // AddressLength is the expected length of the address 39 AddressLength = 20 40 ) 41 42 var ( 43 hashT = reflect.TypeOf(Hash{}) 44 addressT = reflect.TypeOf(Address{}) 45 ) 46 47 // Hash represents the 32 byte Keccak256 hash of arbitrary data. 48 type Hash [HashLength]byte 49 50 // BytesToHash sets b to hash. 51 // If b is larger than len(h), b will be cropped from the left. 52 func BytesToHash(b []byte) Hash { 53 var h Hash 54 h.SetBytes(b) 55 return h 56 } 57 58 // BigToHash sets byte representation of b to hash. 59 // If b is larger than len(h), b will be cropped from the left. 60 func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } 61 62 // HexToHash sets byte representation of s to hash. 63 // If b is larger than len(h), b will be cropped from the left. 64 func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } 65 66 // Bytes gets the byte representation of the underlying hash. 67 func (h Hash) Bytes() []byte { return h[:] } 68 69 // Big converts a hash to a big integer. 70 func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) } 71 72 // Hex converts a hash to a hex string. 73 func (h Hash) Hex() string { return hexutil.Encode(h[:]) } 74 75 // TerminalString implements log.TerminalStringer, formatting a string for console 76 // output during logging. 77 func (h Hash) TerminalString() string { 78 return fmt.Sprintf("%x…%x", h[:3], h[29:]) 79 } 80 81 // String implements the stringer interface and is used also by the logger when 82 // doing full logging into a file. 83 func (h Hash) String() string { 84 return h.Hex() 85 } 86 87 // Format implements fmt.Formatter, forcing the byte slice to be formatted as is, 88 // without going through the stringer interface used for logging. 89 func (h Hash) Format(s fmt.State, c rune) { 90 fmt.Fprintf(s, "%"+string(c), h[:]) 91 } 92 93 // UnmarshalText parses a hash in hex syntax. 94 func (h *Hash) UnmarshalText(input []byte) error { 95 return hexutil.UnmarshalFixedText("Hash", input, h[:]) 96 } 97 98 // UnmarshalJSON parses a hash in hex syntax. 99 func (h *Hash) UnmarshalJSON(input []byte) error { 100 return hexutil.UnmarshalFixedJSON(hashT, input, h[:]) 101 } 102 103 // MarshalText returns the hex representation of h. 104 func (h Hash) MarshalText() ([]byte, error) { 105 return hexutil.Bytes(h[:]).MarshalText() 106 } 107 108 // SetBytes sets the hash to the value of b. 109 // If b is larger than len(h), b will be cropped from the left. 110 func (h *Hash) SetBytes(b []byte) { 111 if len(b) > len(h) { 112 b = b[len(b)-HashLength:] 113 } 114 115 copy(h[HashLength-len(b):], b) 116 } 117 118 // Generate implements testing/quick.Generator. 119 func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value { 120 m := rand.Intn(len(h)) 121 for i := len(h) - 1; i > m; i-- { 122 h[i] = byte(rand.Uint32()) 123 } 124 return reflect.ValueOf(h) 125 } 126 127 // Scan implements Scanner for database/sql. 128 func (h *Hash) Scan(src interface{}) error { 129 srcB, ok := src.([]byte) 130 if !ok { 131 return fmt.Errorf("can't scan %T into Hash", src) 132 } 133 if len(srcB) != HashLength { 134 return fmt.Errorf("can't scan []byte of len %d into Hash, want %d", len(srcB), HashLength) 135 } 136 copy(h[:], srcB) 137 return nil 138 } 139 140 // Value implements valuer for database/sql. 141 func (h Hash) Value() (driver.Value, error) { 142 return h[:], nil 143 } 144 145 // ImplementsGraphQLType returns true if Hash implements the specified GraphQL type. 146 func (_ Hash) ImplementsGraphQLType(name string) bool { return name == "Bytes32" } 147 148 // UnmarshalGraphQL unmarshals the provided GraphQL query data. 149 func (h *Hash) UnmarshalGraphQL(input interface{}) error { 150 var err error 151 switch input := input.(type) { 152 case string: 153 err = h.UnmarshalText([]byte(input)) 154 default: 155 err = fmt.Errorf("Unexpected type for Bytes32: %v", input) 156 } 157 return err 158 } 159 160 // UnprefixedHash allows marshaling a Hash without 0x prefix. 161 type UnprefixedHash Hash 162 163 // UnmarshalText decodes the hash from hex. The 0x prefix is optional. 164 func (h *UnprefixedHash) UnmarshalText(input []byte) error { 165 return hexutil.UnmarshalFixedUnprefixedText("UnprefixedHash", input, h[:]) 166 } 167 168 // MarshalText encodes the hash as hex. 169 func (h UnprefixedHash) MarshalText() ([]byte, error) { 170 return []byte(hex.EncodeToString(h[:])), nil 171 } 172 173 /////////// Address 174 175 // Address represents the 20 byte address of an Ethereum account. 176 type Address [AddressLength]byte 177 178 // BytesToAddress returns Address with value b. 179 // If b is larger than len(h), b will be cropped from the left. 180 func BytesToAddress(b []byte) Address { 181 var a Address 182 a.SetBytes(b) 183 return a 184 } 185 186 // BigToAddress returns Address with byte values of b. 187 // If b is larger than len(h), b will be cropped from the left. 188 func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } 189 190 // HexToAddress returns Address with byte values of s. 191 // If s is larger than len(h), s will be cropped from the left. 192 func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } 193 194 // IsHexAddress verifies whether a string can represent a valid hex-encoded 195 // Ethereum address or not. 196 func IsHexAddress(s string) bool { 197 if has0xPrefix(s) { 198 s = s[2:] 199 } 200 return len(s) == 2*AddressLength && isHex(s) 201 } 202 203 // Bytes gets the string representation of the underlying address. 204 func (a Address) Bytes() []byte { return a[:] } 205 206 // Hash converts an address to a hash by left-padding it with zeros. 207 func (a Address) Hash() Hash { return BytesToHash(a[:]) } 208 209 // Hex returns an EIP55-compliant hex string representation of the address. 210 func (a Address) Hex() string { 211 unchecksummed := hex.EncodeToString(a[:]) 212 sha := sha3.NewLegacyKeccak256() 213 sha.Write([]byte(unchecksummed)) 214 hash := sha.Sum(nil) 215 216 result := []byte(unchecksummed) 217 for i := 0; i < len(result); i++ { 218 hashByte := hash[i/2] 219 if i%2 == 0 { 220 hashByte = hashByte >> 4 221 } else { 222 hashByte &= 0xf 223 } 224 if result[i] > '9' && hashByte > 7 { 225 result[i] -= 32 226 } 227 } 228 return "0x" + string(result) 229 } 230 231 // String implements fmt.Stringer. 232 func (a Address) String() string { 233 return a.Hex() 234 } 235 236 // Format implements fmt.Formatter, forcing the byte slice to be formatted as is, 237 // without going through the stringer interface used for logging. 238 func (a Address) Format(s fmt.State, c rune) { 239 fmt.Fprintf(s, "%"+string(c), a[:]) 240 } 241 242 // SetBytes sets the address to the value of b. 243 // If b is larger than len(a) it will panic. 244 func (a *Address) SetBytes(b []byte) { 245 if len(b) > len(a) { 246 b = b[len(b)-AddressLength:] 247 } 248 copy(a[AddressLength-len(b):], b) 249 } 250 251 // MarshalText returns the hex representation of a. 252 func (a Address) MarshalText() ([]byte, error) { 253 return hexutil.Bytes(a[:]).MarshalText() 254 } 255 256 // UnmarshalText parses a hash in hex syntax. 257 func (a *Address) UnmarshalText(input []byte) error { 258 return hexutil.UnmarshalFixedText("Address", input, a[:]) 259 } 260 261 // UnmarshalJSON parses a hash in hex syntax. 262 func (a *Address) UnmarshalJSON(input []byte) error { 263 return hexutil.UnmarshalFixedJSON(addressT, input, a[:]) 264 } 265 266 // Scan implements Scanner for database/sql. 267 func (a *Address) Scan(src interface{}) error { 268 srcB, ok := src.([]byte) 269 if !ok { 270 return fmt.Errorf("can't scan %T into Address", src) 271 } 272 if len(srcB) != AddressLength { 273 return fmt.Errorf("can't scan []byte of len %d into Address, want %d", len(srcB), AddressLength) 274 } 275 copy(a[:], srcB) 276 return nil 277 } 278 279 // Value implements valuer for database/sql. 280 func (a Address) Value() (driver.Value, error) { 281 return a[:], nil 282 } 283 284 // ImplementsGraphQLType returns true if Hash implements the specified GraphQL type. 285 func (a Address) ImplementsGraphQLType(name string) bool { return name == "Address" } 286 287 // UnmarshalGraphQL unmarshals the provided GraphQL query data. 288 func (a *Address) UnmarshalGraphQL(input interface{}) error { 289 var err error 290 switch input := input.(type) { 291 case string: 292 err = a.UnmarshalText([]byte(input)) 293 default: 294 err = fmt.Errorf("Unexpected type for Address: %v", input) 295 } 296 return err 297 } 298 299 // UnprefixedAddress allows marshaling an Address without 0x prefix. 300 type UnprefixedAddress Address 301 302 // UnmarshalText decodes the address from hex. The 0x prefix is optional. 303 func (a *UnprefixedAddress) UnmarshalText(input []byte) error { 304 return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:]) 305 } 306 307 // MarshalText encodes the address as hex. 308 func (a UnprefixedAddress) MarshalText() ([]byte, error) { 309 return []byte(hex.EncodeToString(a[:])), nil 310 } 311 312 // MixedcaseAddress retains the original string, which may or may not be 313 // correctly checksummed 314 type MixedcaseAddress struct { 315 addr Address 316 original string 317 } 318 319 // NewMixedcaseAddress constructor (mainly for testing) 320 func NewMixedcaseAddress(addr Address) MixedcaseAddress { 321 return MixedcaseAddress{addr: addr, original: addr.Hex()} 322 } 323 324 // NewMixedcaseAddressFromString is mainly meant for unit-testing 325 func NewMixedcaseAddressFromString(hexaddr string) (*MixedcaseAddress, error) { 326 if !IsHexAddress(hexaddr) { 327 return nil, fmt.Errorf("Invalid address") 328 } 329 a := FromHex(hexaddr) 330 return &MixedcaseAddress{addr: BytesToAddress(a), original: hexaddr}, nil 331 } 332 333 // UnmarshalJSON parses MixedcaseAddress 334 func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error { 335 if err := hexutil.UnmarshalFixedJSON(addressT, input, ma.addr[:]); err != nil { 336 return err 337 } 338 return json.Unmarshal(input, &ma.original) 339 } 340 341 // MarshalJSON marshals the original value 342 func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) { 343 if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") { 344 return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:])) 345 } 346 return json.Marshal(fmt.Sprintf("0x%s", ma.original)) 347 } 348 349 // Address returns the address 350 func (ma *MixedcaseAddress) Address() Address { 351 return ma.addr 352 } 353 354 // String implements fmt.Stringer 355 func (ma *MixedcaseAddress) String() string { 356 if ma.ValidChecksum() { 357 return fmt.Sprintf("%s [chksum ok]", ma.original) 358 } 359 return fmt.Sprintf("%s [chksum INVALID]", ma.original) 360 } 361 362 // ValidChecksum returns true if the address has valid checksum 363 func (ma *MixedcaseAddress) ValidChecksum() bool { 364 return ma.original == ma.addr.Hex() 365 } 366 367 // Original returns the mixed-case input string 368 func (ma *MixedcaseAddress) Original() string { 369 return ma.original 370 }