github.com/ledgerwatch/erigon-lib@v1.0.0/common/address.go (about) 1 /* 2 Copyright 2021 Erigon contributors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package common 18 19 import ( 20 "bytes" 21 "database/sql/driver" 22 "encoding/hex" 23 "fmt" 24 "math/big" 25 "reflect" 26 27 "github.com/ledgerwatch/erigon-lib/common/hexutility" 28 "github.com/ledgerwatch/erigon-lib/common/length" 29 "github.com/ledgerwatch/erigon-lib/crypto/cryptopool" 30 ) 31 32 var ( 33 addressT = reflect.TypeOf(Address{}) 34 ) 35 36 // Address represents the 20 byte address of an Ethereum account. 37 type Address [length.Addr]byte 38 39 // BytesToAddress returns Address with value b. 40 // If b is larger than len(h), b will be cropped from the left. 41 func BytesToAddress(b []byte) Address { 42 var a Address 43 a.SetBytes(b) 44 return a 45 } 46 47 // BigToAddress returns Address with byte values of b. 48 // If b is larger than len(h), b will be cropped from the left. 49 func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } 50 51 // HexToAddress returns Address with byte values of s. 52 // If s is larger than len(h), s will be cropped from the left. 53 func HexToAddress(s string) Address { return BytesToAddress(hexutility.FromHex(s)) } 54 55 // IsHexAddress verifies whether a string can represent a valid hex-encoded 56 // Ethereum address or not. 57 func IsHexAddress(s string) bool { 58 if hexutility.Has0xPrefix(s) { 59 s = s[2:] 60 } 61 return len(s) == 2*length.Addr && hexutility.IsHex(s) 62 } 63 64 // Bytes gets the string representation of the underlying address. 65 func (a Address) Bytes() []byte { return a[:] } 66 67 // Hash converts an address to a hash by left-padding it with zeros. 68 func (a Address) Hash() Hash { return BytesToHash(a[:]) } 69 70 // Hex returns an EIP55-compliant hex string representation of the address. 71 func (a Address) Hex() string { 72 return string(a.checksumHex()) 73 } 74 75 // String implements fmt.Stringer. 76 func (a Address) String() string { 77 return a.Hex() 78 } 79 80 func (a *Address) checksumHex() []byte { 81 buf := a.hex() 82 83 // compute checksum 84 sha := cryptopool.GetLegacyKeccak256() 85 //nolint:errcheck 86 sha.Write(buf[2:]) 87 hash := sha.Sum(nil) 88 cryptopool.ReturnLegacyKeccak256(sha) 89 90 for i := 2; i < len(buf); i++ { 91 hashByte := hash[(i-2)/2] 92 if i%2 == 0 { 93 hashByte = hashByte >> 4 94 } else { 95 hashByte &= 0xf 96 } 97 if buf[i] > '9' && hashByte > 7 { 98 buf[i] -= 32 99 } 100 } 101 return buf 102 } 103 104 func (a Address) hex() []byte { 105 var buf [len(a)*2 + 2]byte 106 copy(buf[:2], "0x") 107 hex.Encode(buf[2:], a[:]) 108 return buf[:] 109 } 110 111 // Format implements fmt.Formatter. 112 // Address supports the %v, %s, %v, %x, %X and %d format verbs. 113 func (a Address) Format(s fmt.State, c rune) { 114 switch c { 115 case 'v', 's': 116 s.Write(a.checksumHex()) 117 case 'q': 118 q := []byte{'"'} 119 s.Write(q) 120 s.Write(a.checksumHex()) 121 s.Write(q) 122 case 'x', 'X': 123 // %x disables the checksum. 124 hex := a.hex() 125 if !s.Flag('#') { 126 hex = hex[2:] 127 } 128 if c == 'X' { 129 hex = bytes.ToUpper(hex) 130 } 131 s.Write(hex) 132 case 'd': 133 fmt.Fprint(s, ([len(a)]byte)(a)) 134 default: 135 fmt.Fprintf(s, "%%!%c(address=%x)", c, a) 136 } 137 } 138 139 // SetBytes sets the address to the value of b. 140 // If b is larger than len(a), b will be cropped from the left. 141 func (a *Address) SetBytes(b []byte) { 142 if len(b) > len(a) { 143 b = b[len(b)-length.Addr:] 144 } 145 copy(a[length.Addr-len(b):], b) 146 } 147 148 // MarshalText returns the hex representation of a. 149 func (a Address) MarshalText() ([]byte, error) { 150 b := a[:] 151 result := make([]byte, len(b)*2+2) 152 copy(result, hexPrefix) 153 hex.Encode(result[2:], b) 154 return result, nil 155 } 156 157 // UnmarshalText parses a hash in hex syntax. 158 func (a *Address) UnmarshalText(input []byte) error { 159 return hexutility.UnmarshalFixedText("Address", input, a[:]) 160 } 161 162 // UnmarshalJSON parses a hash in hex syntax. 163 func (a *Address) UnmarshalJSON(input []byte) error { 164 return hexutility.UnmarshalFixedJSON(addressT, input, a[:]) 165 } 166 167 // Scan implements Scanner for database/sql. 168 func (a *Address) Scan(src interface{}) error { 169 srcB, ok := src.([]byte) 170 if !ok { 171 return fmt.Errorf("can't scan %T into Address", src) 172 } 173 if len(srcB) != length.Addr { 174 return fmt.Errorf("can't scan []byte of len %d into Address, want %d", len(srcB), length.Addr) 175 } 176 copy(a[:], srcB) 177 return nil 178 } 179 180 // Value implements valuer for database/sql. 181 func (a Address) Value() (driver.Value, error) { 182 return a[:], nil 183 }